I'm trying to learn about C and how to use its functions, etc. The man pages suggested to use strtol
instead of atoi
, so I came up with this code which works without issues:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
int main()
{
const char str[] = "12aaa";
long size = sizeof(str) / sizeof(char);
char **ptr = malloc(size);
if (!ptr) {
perror("ERROR! Could not reserve memory for ptr!");
return EXIT_FAILURE;
}
memset(ptr, 0, size);
printf("str: %s\n", str);
printf("strtol: %ld\n", strtol(str, ptr, 10));
printf("ptr container: %s\n", *ptr);
free(ptr);
return EXIT_SUCCESS;
}
This successfully output:
str: 12aaa
strtol: 12
ptr container: aaa
After, I came up with a question: since strtol
asks for a double ptr to char, can I just use the address of a string variable (container)? If I make sure that the container string is the same length, in theory there should be no overflow (if main string is longer etc). So I edited the code to use a local string variable and pass the address as such:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
int main()
{
const char str[] = "12aaa";
// using char instead of const char because it should be changeable?
char container[] = "aaaaa"; //same length of str
long size = sizeof(str) / sizeof(char);
printf("strtol: %ld\n", strtol(str, &container, 10));
printf("container: %s\n", container);
return EXIT_SUCCESS;
}
Here I get this message:
strtol: 12
container: $g��
*** stack smashing detected ***: terminated
I thought that the container variable should remain until main
is terminated? Why does this not work as intended?
From what I understand, which is only beginner level, container is a stack variable, so it only exists until a function/main
executes and then goes away. Since it is in main
, why is it not working properly?
Is the stack protected/unable to be used by pointers?
Why does this only work for heap allocated memory locations?
Is there something wrong in my reasoning?
Thanks for any clarifications in advanced!
UPDATE:
I'm running macos and when I run man strtol
I don't get any examples and this paragraph is near the end of the Description: If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, however, strtol() stores the original value of str in *endptr.
The last sentence's wording make me thing that strtol does copy the original str, which is why I thought maybe allocating memory would work.
I obviously did not understand how to use endptr or what its function was properly, but thanks for your answers/comments! It seems that I need more work to understand the differences between C strings, arrays, and pointers!
It seems you're misunderstanding what the second parameter to strtol
is for.
It is not a pointer to memory location that holds a copy of the string after the end of the match. It is simply a pointer to a pointer which points to a location in the original string where the match ended.
In both cases, you're passing a pointer which points to an object 6 bytes in length. Assuming you're using a modern system that uses 64-bit addressing, that's two bytes less than what is required to hold a char *
. This triggers undefined behavior in your code. In the first case it appears to work normally, while in the second it causes a crash.
What you really need here is simply a char *
variable whose address is passed to the function.
char *ptr;
printf("strtol: %ld\n", strtol(str, &ptr, 10));
printf("ptr points to: %s\n", ptr);