I have this code:
#define ABC "abc"
void main()
{
char *s = malloc(sizeof(char)*3);
printf("%p ", s);
s = ABC;
printf("%p ", s);
free(s);
}
This is the output:
0x8927008 0x8048574 Segmentation fault (core dumped)
As you can see, the address of string s changes after assignment (I think this is why free() gives segfault).
Can anyone explain me why and how this happens?
Thank you!
The line
s = ABC;
changes s to point to a different string which may well be in read-only memory. Attempting to free such memory results in undefined behaviour. A crash is likely.
I think you wanted
strcpy(s, ABC);
instead. This would copy the char array "abc" into s. Note that this will cause a further bug - s is too short and doesn't have space for the nul terminator at the end of ABC. Change you allocation to 4 bytes to fix this
char *s = malloc(4);
or use
char *s = malloc(sizeof(ABC));
if ABC is the max length you want to store.
void main() UB: main returns int
printf("%p", s) UB: calling a function accepting a variable number of arguments without a prototype in scope; UB: using a value of type char* where a value of type void* is expected.
free(s) UB: s is not the result of a malloc()
UB is Undefined Behaviour.
After
char *s = malloc(sizeof(char)*3);
s points to the memory allocated by malloc.
The line
s = ABC;
will change to
s = "abc";
after the prepossessing. Now this step makes s point to the string literal "abc" in the read-only area. Note that this also leaks the malloced memory.
Now since s is pointing to a non-malloced read-only memory, free it is a undefined behavior.
If you wanted to copy the string "abc" into memory pointed to by s you need to use strcpy as:
strcpy(s, ABC);
but note that to accommodate "abc", s must be at least 4 characters long, to accommodate the NUL character as well.
Change the line: char *s = malloc(sizeof(char)*3);
to
char *s = (char *)malloc(sizeof(char)*3);
This clears up warnings many compilers warn about.
More than that I recommend that you make your code more flexible depending on what you do. If for some reason you change ABC to "ABCD", you will not have allocated enough space for all the characters.
Also, the string "ABC" has actually 4 characters (since there is a null at the end that terminates the strings). You'll see issues without that extra terminator.
Related
char *p="This is anonymous string literal";
Doing this I can access this string easily but tell me that how can I get string literal from user using this p pointer without declaring the other variable for string. Check my images from button to top.
A string literal declares a const character array. That means that any try to change the characters through the p pointer would invoke Undefined Behaviour (the hell for C programmers...).
To be able to read a string from the user (note, not a literal one), you must either declare a character array, or allocate one with malloc and friends.
Examples:
char str[80];
char *p = str; // Ok, you can do what you want with 79 charactes (last should be null)
or
char *p = malloc(80); // again 80 characters to play with
...
free(p); // but you are responsable for releasing allocated memory when done
Changing the size of your string requires memory allocation.
Maybe you could just use a pointer to this string in your program and change the target of the pointer.
That may not answer your question but it can be interesting.
char *str = "My string";
char *str2 = "My string 2";
char **ptr = &str;
printf("%s\n", *ptr);
ptr = &str2;
printf("%s\n", *ptr);
Edit
From gets() documentation:
str − This is the pointer to an array of chars where the C string is stored
Means that the pointer passed as parameters of gets() must already have allocated memory, you could try:
char p[50];
// instead of
char *p; // No memory allocated to put user input in
That's why you got a segfault (with memory observation tools like valgrind you'll see errors on all compilers).
Also printf() is not flushing the output without a carriage return (\n), you could try:
printf("No carriage return");
fflush(stdout); // Force stdout update
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?
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);
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";
I'm not quite sure I get how malloc works exactly.
#include <stdio.h>
#include <stdlib.h>
int main() {
char * string = (char*) malloc(sizeof(char));
string = "abc";
int * test = (int*) malloc(1 * sizeof(int));
*(test) = 5;
*(test + 1) = 6;
}
I expected this to output an error since the value I appoint to string is bigger than just one char yet it seems to compile just fine.
I have a few questions:
Where would 'string' be saved now? is it on memory spaces on the heap after the one space I allocated ?
Why is does the char let me appoint directly and the int only via pointer?
I'm really not sure what I'm doing here
This code
string = "abc";
assigns the address of the string constant "abc" to the string variable, which is a char *. The address of the memory returned from your malloc() call - which was in string - gets overwritten and lost.
In addition to the other answers:
You probably want this:
char *string = (char*) malloc(sizeof(char) * 100); // allocate space for 100 chars
strcpy(string, "abc"); // copy the "abc" into the memoory location pointer by string
instead of this:
char *string = (char*) malloc(sizeof(char)); // << this allocates only a single char
string = "abc";
And
*(test) = 5;
*(test + 1) = 6;
is better written as:
test[0] = 5;
test[1] = 6;
which is strictly equivalent, it's just a matter of readability.
Allocating too few memory:
If you allocate memory for only 1 char as here:
char *string = (char*) malloc(sizeof(char)); // allocate space 1 char
strcpy(string, "abc"); // copy the "abc" into the memoory location pointer by string
then your program will still compile fine, but at runtime the string will be copied partly to non allocated memory, which results in undefined behaviour (google "undefined behaviour").
Where would 'string' be saved now?
char * string = (char*) malloc(sizeof(char));
string = "abc";
string now points to "abc" (a literal string) - the initial dynamic allocation (in the heap) has been lost track and you have a memory leak.
I will give you a real-life example.
Suppose Mr. A lives at the address "abc". Now, some Mr. B starts living at some address "xyz". Soon, Mr. B address "xyz" is renamed to "abc". Now, if you go to the address "abc", you will meet Mr. B, not Mr. A. But, this don't mean that Mr. A place is demolished. It simply means that Mr. A's living area now has no reachable address and is lost.
Similarly, the memory you malloc'ed to string and then re-assigned the string to "abc", means, string earlier had an address to the malloc'ed memory. Later, your "abc" is written to some memory and the address to that memory is stored in string. Thus, losing the malloc'ed memory forever which is called Memory Leak.
The compiler will not prevent you to do something that is allowed - however you're likely to get a warning for the 1) since string is assigned and not used before being re-assigned (provided that the compiler is requested to output the relevant warnings).
As for 2), you call a function which happens to be malloc, with an argument that happens to be too small for the usage you want to do with the pointer returned by malloc, but since the syntax is correct, the compiler doesn't complain.
Answer to
1) string points to "abc" and the previous value from malloc is lost
2) you could do test[0] = 5; as well.
The behavior for 2) is undefined behavior (access an array out of bounds).
At first there was allocated dynamically memory with the requested size of one character.
char * string = (char*) malloc(sizeof(char));
And then the pointer was reassigned with the address of the first character of the string literal "abc".
string = "abc";
As result the address of the dynamically allocated memory was lost and there is a memory leak in the program.
If the program would written in C++ then this statement
string = "abc";
could arise a compiler diagnostic message because string literals in C++ have types of constant character arrays and the pointer string shuld be declared like
const char *string;
As for the string literal then they have static storage duration and are allocated before main gets the control. Usually all string literals are places in the so-called string literal pool.
Instead of this statement
string = "abc";
you could write
strcpy( string, "abc" );
In this case the program has undefined behavior. However it can continue to work successfully due to the feature that usually the function malloc allocates minimum memory extent equal to the value of the paragraph that is equal to 16 bytes.
I am sorry, I might me asking a dumb question but I want to understand is there any difference in the below assignments? strcpy works in the first case but not in the second case.
char *str1;
*str1 = "Hello";
char *str2 = "World";
strcpy(str1,str2); //Works as expected
char *str1 = "Hello";
char *str2 = "World";
strcpy(str1,str2); //SEGMENTATION FAULT
How does compiler understand each assignment?Please Clarify.
Edit: In the first snippet you wrote *str1 = "Hello" which is equivalent to assigning to str[0], which is obviously wrong, because str1 is uninitialized and therefore is an invalid pointer. If we assume that you meant str1 = "Hello", then you are still wrong:
According to C specs, Attempting to modify a string literal results in undefined behavior: they may be stored in read-only storage (such as .rodata) or combined with other string literals so both snippets that you provided will yield undefined behavior.
I can only guess that in the second snippet the compiler is storing the string in some read-only storage, while in the first one it doesn't, so it works, but it's not guaranteed.
Sorry, both examples are very wrong and lead to undefined behaviour, that might or might not crash. Let me try to explain why:
str1 is a dangling pointer. That means str1 points to somewhere in your memory, writing to str1 can have arbitrary consequences. For example a crash or overriding some data in memory (eg. other local variables, variables in other functions, everything is possible)
The line *str1 = "Hello"; is also wrong (even if str1 were a valid pointer) as *str1 has type char (not char *) and is the first character of str1 which is dangling. However, you assign it a pointer ("Hello", type char *) which is a type error that your compiler will tell you about
str2 is a valid pointer but presumably points to read-only memory (hence the crash). Normally, constant strings are stored in read-only data in the binary, you cannot write to them, but that's exactly what you do in strcpy(str1,str2);.
A more correct example of what you want to achieve might be (with an array on the stack):
#define STR1_LEN 128
char str1[STR1_LEN] = "Hello"; /* array with space for 128 characters */
char *str2 = "World";
strncpy(str1, str2, STR1_LEN);
str1[STR1_LEN - 1] = 0; /* be sure to terminate str1 */
Other option (with dynamically managed memory):
#define STR1_LEN 128
char *str1 = malloc(STR1_LEN); /* allocate dynamic memory for str1 */
char *str2 = "World";
/* we should check here that str1 is not NULL, which would mean 'out of memory' */
strncpy(str1, str2, STR1_LEN);
str1[STR1_LEN - 1] = 0; /* be sure to terminate str1 */
free(str1); /* free the memory for str1 */
str1 = NULL;
EDIT: #chqrlie requested in the comments that the #define should be named STR1_SIZE not STR1_LEN. Presumably to reduce confusion because it's not the length in characters of the "string" but the length/size of the buffer allocated. Furthermore, #chqrlie requested not to give examples with the strncpy function. That wasn't really my choice as the OP used strcpy which is very dangerous so I picked the closest function that can be used correctly. But yes, I should probably have added, that the use of strcpy, strncpy, and similar functions is not recommended.
There seems to be some confusion here. Both fragments invoke undefined behaviour. Let me explain why:
char *str1; defines a pointer to characters, but it is uninitialized. It this definition occurs in the body of a function, its value is invalid. If this definition occurs at the global level, it is initialized to NULL.
*str1 = "Hello"; is an error: you are assigning a string pointer to the character pointed to by str1. str1 is uninitialized, so it does not point to anything valid, and you channot assign a pointer to a character. You should have written str1 = "Hello";. Furthermore, the string "Hello" is constant, so the definition of str1 really should be const char *str1;.
char *str2 = "World"; Here you define a pointer to a constant string "World". This statement is correct, but it would be better to define str2 as const char *str2 = "World"; for the same reason as above.
strcpy(str1,str2); //Works as expected NO it does not work at all! str1 does not point to a char array large enough to hold a copy of the string "World" including the final '\0'. Given the circumstances, this code invokes undefined behaviour, which may or may not cause a crash.
You mention the code works as expected: it only does no in appearance: what really happens is this: str1 is uninitialized, if it pointed to an area of memory that cannot be written, writing to it would likely have crashed the program with a segmentation fault; but if it happens to point to an area of memory where you can write, and the next statement *str1 = "Hello"; will modify the first byte of this area, then strcpy(str1, "World"); will modify the first 6 bytes at that place. The string pointed to by str1 will then be "World", as expected, but you have overwritten some area of memory that may be used for other purposes your program may consequently crash later in unexpected ways, a very hard to find bug! This is definitely undefined behaviour.
The second fragment invokes undefined behaviour for a different reason:
char *str1 = "Hello"; No problem, but should be const.
char *str2 = "World"; OK too, but should also be const.
strcpy(str1,str2); //SEGMENTATION FAULT of course it is invalid: you are trying to overwrite the constant character string "Hello" with the characters from the string "World". It would work if the string constant was stored in modifiable memory, and would cause even greater confusion later in the program as the value of the string constant was changed. Luckily, most modern environemnts prevent this by storing string constants in a read only memory. Trying to modify said memory causes a segment violation, ie: you are accessing the data segment of memory in a faulty way.
You should use strcpy() only to copy strings to character arrays you define as char buffer[SOME_SIZE]; or allocate as char *buffer = malloc(SOME_SIZE); with SOME_SIZE large enough to hold what you are trying to copy plus the final '\0'
Both code are wrong, even if "it works" in your first case. Hopefully this is only an academic question! :)
First let's look at *str1 which you are trying to modify.
char *str1;
This declares a dangling pointer, that is a pointer with the value of some unspecified address in the memory. Here the program is simple there is no important stuff, but you could have modified very critical data here!
char *str = "Hello";
This declares a pointer which will point to a protected section of the memory that even the program itself cannot change during execution, this is what a segmentation fault means.
To use strcpy(), the first parameter should be a char array dynamically allocated with malloc(). If fact, don't use strcpy(), learn to use strncpy() instead because it is safer.
Why does the following happen:
char s[2] = "a";
strcpy(s,"b");
printf("%s",s);
--> executed without problem
char *s = "a";
strcpy(s,"b");
printf("%s",s);
--> segfault
Shouldn't the second variation also allocate 2 bytes of memory for s and thus have enough memory to copy "b" there?
char *s = "a";
The pointer s is pointing to the string literal "a". Trying to write to this has undefined behaviour, as on many systems string literals live in a read-only part of the program.
It is an accident of history that string literals are of type char[N] rather than const char[N] which would make it much clearer.
Shouldn't the second variation also allocate 2 bytes of memory for s and thus have enough memory to copy "b" there?
No, char *s is pointing to a static memory address containing the string "a" (writing to that location results in the segfault you are experiencing) whereas char s[2]; itself provides the space required for the string.
If you want to manually allocate the space for your string you can use dynamic allocation:
char *s = strdup("a"); /* or malloc(sizeof(char)*2); */
strcpy(s,"b");
printf("%s",s); /* should work fine */
Don't forget to free() your string afterwards.
Altogather a different way/answer : I think the mistake is that you are not creating a variable the pointer has to point to and hence the seg fault.
A rule which I follow : Declaring a pointer variable will not create the type of variable, it points at. It creates a pointer variable. So in case you are pointing to a string buffer you need to specify the character array and a buffer pointer and point to the address of the character array.