Currently reading K&R and just got stumbled across the char pointers. There's nothing about memory allocation when defining char pointers in the book rn, maybe it'll be explained later. But it just doesn't make sense so I'm seeking help :)
1
// No errors
char *name;
char *altname;
strcpy(altname,name);
2
// No errors, internals of *name have been successfully moved to *altname
char *name = "HI";
char *altname;
strcpy(altname, name);
3
// Segmentation fault, regardless of how I define *altname
char *name = "HI";
char *altname = "randomstring";
strcpy(altname, name);
4
// Segmentation fault, regardless of how I define *altname
char *name;
char *altname = " ";
strcpy(altname, name);
5
// copies internals of *name only if size of char s[] > 8???
char s[9];
char n[] = {'c', 'b'};
char *name = n;
char *altname = s;
strcpy(altname, name);
Why does the first example produce no error, even though there's no memory allocated?
Why does the second one successfully copy name to altname, even though there's no memory allocated for altname;
Why do the third and forth one core dump?
Why does the fifth one require size of s as >8?
CodePudding user response:
I'm a bit surprised that the first two examples worked. strcpy
takes the character array pointed to by the second argument and copies it to the character array pointed to by the first argument.
In your first example, the pointers name
and altname
aren't pointing to anything. They're uninitialized pointers. Now they have some value based on either whatever gunk was in memory when the main
function was executed or just however the compiler decided to initialize them. That's why I'm surprised that your code isn't crashing.
Anyway, the reason why your third example is segfaulting is you've set both pointers to point to string literals (i.e., "HI"
and "randomstring"
). String literals are (most likely) stored in a read-only section of memory. So, when you run strcpy
with the destination pointer set to altname
, you're trying to write to read-only memory. That's an invalid use of memory and hence the crash. The same goes for your fourth example.
In the final example, your problem is that n
is not null-terminated. strcpy
keeps copying characters until it reaches a terminator (i.e., '\0'
). You've put a 'c'
and a 'b'
in your array but no terminator. Therefore, strcpy
is going to keep copying even after it's reached the end of n
. The fact that it works when sizeof(s)
is greater than 8 probably involves where a null byte happens to exist on your stack. That is, if you make s
too small, you'll write past the end of it and corrupt the memory on your stack. It's possible you're overriding your return pointer and thus returning to some invalid memory address when your function is done executing.
What you need to do is, instead of using pointers, use arrays. This will give you the storage space you need in a writable section of memory. You also need to make sure that your arrays are null-terminated. This can be done automatically by initializing your arrays with string literals.
char name[] = "HI";
char altname[] = "randomstring";
strcpy(altname, name);
char s[3]; // Enough space to hold "cb" plus a null-terminator.
char n[] = "cb";
char *name = n;
char *altname = s;
strcpy(altname, name);
CodePudding user response:
All code snippets are undefined behavior. There is no guarantee that you will get an error. As the term says, the behavior is undefined.
In 1 and 2, one or both pointers are uninitialized and may point to memory that may or may not be protected against the programmed access, so you may or may not get an error or program crash.
In 3 and 4 you may get a reproducible segmentation fault because altname
points to a string literal "randomstring"
or " "
which can be read-only, so you are not allowed to overwrite the memory where altname
points to. In 4, name
is uninitialized, so this might also be the cause of the segmentation fault.
In 5, n
is not a valid string that could be used for strcpy
. The terminating '\0'
is missing. strcpy
will (try to) copy everything after the end of n
until it finds a '\0'
. To fix it use
char n[] = {'c', 'b', '\0'};
or
char n[] = "cb";