mallocing string in C - c

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.

Related

Using malloc to initialize char pointer VS not using malloc and just assign a string directly to the char pointer

I'm trying to understand how this memory allocation thing works when it comes to char and strings.
I know that the name of a declared array is just like a pointer to the first element of the array, but that array will live in the stack of the memory.
On the other hand, we use malloc when we want to use the heap of the memory, but I found that you can just initialize a char pointer and assign a string to it on the very same declaration line, so I have some questions regarding this matter:
1) If I just initialize a char pointer and assign a string to it, where is this information living? In the heap? In the stack?
Ex: char *pointer = "Hello world";
2) I tried to use malloc to initialize my char pointer and use it later to assign a string to it, but I can't compile it, I get error, what is wrong with this logic? this is what I'm trying to do:
char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";
Can you please help me understand more about pointers and memory allocation? Thank you very much! :)
1) If I just initialize a char pointer and assign a string to it,
where is this information living? In the heap? In the stack? Ex: char
*pointer = "Hello world";
Neither on the stack or on the heap. "Hello world" is a string literal, generally created in the rodata (read-only data) segment of the executable. In fact, unless you specify differently, the compiler is free to only store a single copy of "Hello world" even if you assign it to multiple pointers. While typically you cannot assign strings to pointers, since this is a string literal, you are actually assigning the address for the literal itself -- which is the only reason that works. Otherwise, as P__J__ notes, you must copy strings from one location to another.
2) I tried to use malloc to initialize my char pointer and use it
later to assign a string to it, but I can't compile it, I get error,
what is wrong with this logic? this is what I'm trying to do:
char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";
You are mixing apples and oranges here. char *pointer = malloc (12); allocates storage for 12-characters (bytes) and then assigns the beginning address for that new block of storage to pointer as its value. (remember, a pointer is just a normal variable that holds the address to something else as its value)
For every allocation, there must be a validation that the call succeeded, or you will need to handle the failure. Allocation can, and does fail, and when it fails, malloc, calloc * realloc all return NULL. So each time you allocate, you
char *pointer = malloc(12); /* note: sizeof (char) is always 1 */
if (pointer == NULL) { /* you VALIDATE each allocation */
perror ("malloc-pointer");
return 1;
}
Continuing with your case above, you have allocated 12-bytes and assigned the starting address for the new memory block to pointer. Then, you inexplicably, derefernce pointer (e.g. *pointer which now has type char) and attempt to assign the address of the string literal as that character.
*pointer = "Hello world"; /* (invalid conversion between pointer and `char`) */
What you look like you want to do is to copy "Hello world" to the new block of memory held by pointer. To do so, since you already know "Hello world" is 12-characters (including the nul-terminating character), you can simply:
memcpy (pointer, "Hello world", 12);
(note: if you already have the length, there is no need to call strcpy and cause it to scan for the end-of-string, again)
Now your new allocated block of memory contains "Hello world", and the memory is mutable, so you can change any of the characters you like.
Since you have allocated the storage, it is up to you to free (pointer); when that memory is no longer in use.
That in a nutshell is the difference between assigning the address of a string literal to a pointer, or allocating storage and assigning the first address in the block of new storage to your pointer, and then copying anything you like to that new block (so long as you remain within the allocated bounds of the memory block allocated).
Look things over and let me know if you have further questions.
1) If I just initialize a char pointer and assign a string to it, where is this information living? In the heap? In the stack? Ex: char *pointer = "Hello world";
The string literal "Hello world" has static storage duration. This means it exists somewhere in memory accessible to your program, for as long as your program is running.
The exact place where it is located is implementation specific.
2) I tried to use malloc to initialize my char pointer and use it later to assign a string to it, but I can't compile it, I get error, what is wrong with this logic? this is what I'm trying to do:
char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";
This doesn't work, since *pointer is the first char in the dynnamically allocated memory (returned by malloc()). The string literal "Hello world" is represented as an array of characters. An array of characters cannot be stored in a single char.
What you actually need to do in this case is copy data from the string literal to the dynamically allocated memory.
char *pointer = malloc(sizeof(char) * 12);
strcpy(pointer, "Hello world"); /* strcpy() is declared in standard header <string.h> *
Note that this doesn't change the data that represents the string literal. It copies the data in that string literal into the memory pointed at by pointer (and allocated dynamically by malloc()).
If you really want pointer to point at the (first character of) the string literal, then do
const char *pointer = "Hello world";
The const represents the fact that modifying a string literal gives undefined behaviour (and means the above prevents using pointer to modify that string literal).
If you want to write really bad code you could also do
char *pointer = "Hello world"; /* Danger Will Robinson !!!! */
or (same net effect)
char *pointer;
pointer = "Hello world"; /* Danger Will Robinson !!!! */
This pointer can now be used to modify contents of the string literal - but that causes undefined behaviour. Most compilers (if appropriately configured) will give warnings about this - which is one of many hints that you should not do this.
Long question but the answer is very easy. Firstly you need to understand what the pointer is.
*pointer = "Hello world";
Here you try to assign a pointer to the char. If you remove the * then you will assign the pointer to the string literal to the pointer.
Unless you have overloaded the assign operator it will not copy it to the allocated memory. Your malloc is pointless as you assign new value to the pointer and the memory allocated by the malloc is lost
You need to strcpy it instead
where is this information living?
It is implementation dependant where the string literals are stored. It can be anywhere. Remember that you can't modify the string literals. Attempt to do so is an Undefined Behaviour
I know that the name of a declared array is just like a pointer to the first element of the array,…
This is not correct. An array behaves similarly to a pointer in many expressions (because it is automatically converted), but it is not just like a pointer to the first element. When used as the operand of sizeof or unary &, an array will be an array; it will not be converted to a pointer. Additionally, an array cannot be assigned just like a pointer can; you cannot assign a value to an array.
… but that array will live in the stack of the memory.
The storage of an array depends on its definition. If an object is defined outside of any function, it has static storage duration, meaning it exists for the entire execution of the program. If it is defined inside a function without _Thread_local or static has automatic storage duration, meaning it exists until execution of its associated block of code ends. C implementations overwhelmingly use the stack for objects of automatic storage duration (neglecting the fact that optimization can often make use of the stack unnecessary), but alternatives are possible.
On the other hand, we use malloc when we want to use the heap of the memory, but I found that you can just initialize a char pointer and assign a string to it on the very same declaration line, so I have some questions regarding this matter:
1) If I just initialize a char pointer and assign a string to it, where is this information living? In the heap? In the stack? Ex: char *pointer = "Hello world";
For the string literal "Hello world", the C implementation creates an array of characters with static storage duration, the same as if you had written char MyString[12]; or int x; at file scope. Assuming this array is not eliminated or otherwise altered by optimization, it is in some general area of memory that the C implementation uses for data built into the program (possibly a “.rodata” or similar read-only section).
Then, for char *pointer, the C implementation creates a pointer. If this definition appears outside a function, it has static storage duration, and the C implementation uses some general area of memory for that. If it appears inside a function, it has automatic storage duration, and the C implementation likely uses stack space for it.
Then, for the = "Hello world", the C implementation uses the array to initialize pointer. To do this, it converts the array to a pointer to its first element, and it uses that pointer as the initial value of pointer.
2) I tried to use malloc to initialize my char pointer and use it later to assign a string to it, but I can't compile it, I get error, what is wrong with this logic? this is what I'm trying to do:
char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";
The second line is wrong because *pointer has a different role in a declaration than it does in an expression statement.
In char *pointer = …;, *pointer presents a “picture” of what should be a char. This is how declarations work in C. It says *pointer is a char, and therefore pointer is a pointer to a char. However, the thing being defined and initialized is not *pointer but is pointer.
In contrast, in *pointer = "Hello world";, *pointer is an expression. It takes the pointer pointer and applies the * operator to it. Since pointer is a pointer to char, *pointer is a char. Then *pointer = "Hello world"; attempts to assign "Hello world" to a char. This is an error because "Hello world" is not a char.
What you are attempting to do is to assign a pointer to "Hello world" to pointer. (More properly, a pointer to the first character of "Hello world".) To do this, use:
pointer = "Hello world";

Why can we read any char in this allocated pointer and not write to it?

I'm still a newbie to C
char* str = (char*)malloc(512);
str = "hello";
*(str) = 'H'; // Segmentation fault
I get a Segmentation fault on the third line trying to set an character
I know that str is a pointer to the first char and I can printf it
printf("%c\n", *str); // Output: h
Well, Is it in Read-Only memory? I'm not sure why that happened but I can change the whole pointer just like I did
str = "hello";
I can do that
char** str = (char**)malloc(512*sizeof(char*));
*str = "hello";
*(str+1) = "Yo!";
//*(str) = 'H';
printf("%s\n", *(str)); // Prints: hello
printf("%s\n", *(str+1)); // Prints: Yo!
from the last code, I can do this and still the same
str[0] = "hello";
str[1] = "Yo!";
The reason is that it's an array of pointers after all, I'm just changing that pointer like in the first code, with some index
and the reason why *(str+1) = "Yo!"; works, I'm incrementing the address or the 0 index of char* which gives me the address of the next adjacent char*
from the last code, I cannot do things like
**(str) = 'H';
*(str)[0] = 'H';
str[0][0] = 'H';
except if I have an array of char
char str[5][10]; // allocated 5 strings slots, 10 max characters for each
*(str)[0] = 'H';
*(str[0]+1) = 'e';
str[0][2] = 'l';
str[0][3] = 'l';
*((*str)+4 )= 'o';
printf("%s\n", str[0]); // Prints: Hello
I can allocate 512 char and just use 12, I can allocate 1024 char and still need more, I can go out of memory if I allocated too much
I've to use char* and I need to be able to change the value of an char like I did in that last array
like, let's say I'm building an compiler, text editor...
I need to be able to allocate memory at runtime plus check some characters like ';'
Or an split() function, which splits an char* into an array of pointers
Start copying char[s] into char[n][i] // n = 0, ++i, ++s
for each ';' iteration in char*, i = 0, ++n
return char**
This can be done easily if I'm working with 2D arrays, but they're not, they're pointers...
How can we change the value of a char in this pointer?
Why can we read any char in this pointer and not write to it?
I don't have a full understanding of pointers yet, Sorry if something is wrong with the code, thanks.
You get a segfault here
char* str = (char*)malloc(512);
str = "hello";
*(str) = 'H'; // Segmentation fault
because you are setting ptr to point to a string literal, the old value
(returned by malloc) is gone. And modifying string literals is undefined behaviour and
in most systems string literal are in read-only memory anyway, so you cannot
modify them. The segfault is the consequence of that.
Note that str = "hello" is an assignment, you are copying the address of where
the string literal is stored in memory in the pointer str. str is now
pointing to the string literal. But you haven't done a copy of the
contents, for that you need to use a function like strcpy or strncpy:
char* str = malloc(512);
if(str == NULL)
{
// error handling
// do not continue
}
strcpy(str, "hello"); // copying the content of the string literal
*(str) = 'H'; // now it works
And please note that you don't have to cast malloc. And don't forget to
check if malloc returns NULL and to free the memory afterwards.
edit
char str[5][10]; // allocated 5 strings slots, 10 max characters for each
*(str)[0] = 'H';
*(str[0]+1) = 'e';
str[0][2] = 'l';
str[0][3] = 'l';
*((*str)+4 )= 'o';
printf("%s\n", str[0]); // Prints: Hello
Here you have one problem though, you are not setting the '\0'-terminating
byte, the printf yields an undefined behaviour. The correct code should be:
char str[5][10]; // allocated 5 strings slots, 10 max characters for each
*(str)[0] = 'H';
*(str[0]+1) = 'e';
str[0][2] = 'l';
str[0][3] = 'l';
*((*str)+4 )= 'o';
str[0][5] = '\0'; // terminating the string
printf("%s\n", str[0]); // Prints: Hello
edit 2
How can we change the value of an char in a pointer in C?
The problem with your confusion was that you didn't realize that you lost the
pointer to the malloced memory block and tryied to modify a string literal
instead.
How can you change the value of a char in a pointer?
Like this:
char text[] = "This is a long text";
char *ptr = text;
ptr[0] = 't';
this works, because text has been initialized with the contents of the string
literal. ptr is pointing to the start of start of the sequence of characters
stored in text, ptr[0] allows you to access the first character in the
sequence.
Why can we read any char in an pointer and not write to it?
If you don't have wright permission (for example read-only memory) or the
pointer is declared as const, then you cannot obviously write a character
through the pointer. But if the pointer points to valid, writeable memory, then
you can write a character through the pointer.
In order to help with some of the misconceptions you have regarding pointers, I put down a few notes (from a pointers perspective). It's not meant to be facetious or patronizing, but as I went along, telling it from a pointers point of view, just made sense. So let me introduce you to our pointer p:
char *p;
Hello, I am an uninitialize pointer to type char. I am just a varaible that holds the address to something else as my value. So you can assign any address you want to me without having to allocate anything first. For example,
p = "Hello";
I now hold the address of the string-literal "Hello" as my value. "Hello" itself resides in the .rodata section of the executable (read-only). So you cannot change anything I point to now. But, if the memory I point to is mutable, then you are free to iterate over the characters I point to and make any changes you like, e.g.,
char buf[] = "Hello";
p = buf;
Now I hold the address of buf as my value. Since buf is stored on the stack and can be freely changed, e.g.
p[4] = '!';
Now the string pointed to by p tells you were not to go.
Since I can hold the address to anything else (and do so without violating the strict aliasing rule (C11 Standard - §6.5 Expressions (p6,7)), I can also hold the beginning address to a dynamically allocated block of memory. However, you must take care when I do. In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
That means while I point to a dynamically allocated block, you cannot assign another address to me until you either store the address I point to somewhere else, or free the memory I point to. Otherwise, you will have lost the address for the memory I used to point to and it can never be freed again (a memory leak).
I have another important role as a pointer. I provide pointer arithmetic. My type determines the number of bytes involved when I am incremented, decremented or indexed. Since sizeof char is always 1, any pointer arithmetic on a character type only advances or decrements by 1-byte, but if I am a type int, then the increments or decrements move 4-bytes at a time, and so on...
When you use me to allocate storage, always use the size of what I point to in determining the size of the allocation. For instance to allocate 100 chars,
p = malloc (100 * sizeof *p);
It works the same way if I point to a compound type, e.g.
typedef struct {
char word[100];
int nvowels;
} list_t;
...
size_t listsize = 100;
list_t *p = malloc (listsize * sizeof *p);
If you use my size for allocation instead of trying to take the size of some type, I will prevent you from ever getting it wrong.
So that's pretty much a day-in-the-life-of a pointer. (multiple levels of indirection work the same)
char* str = (char*)malloc(512);
str = "hello";
*(str) = 'H'; // Segmentation fault
And then you say:
Well, Is it in Read-Only memory? I'm not sure why that happened but I can change the whole pointer just like I did
Yeah, you literally changed the whole pointer. You now made str point to read-only memory and totally wasted the memory allocated by malloc. Once again, str = "hello"; does not write data into the memory provided by malloc. It just makes str point to something else.

What is the difference between assigning a string pointer first to allocated memory and directly to a string literal?

So my understanding is that these two block of codes are valid and do the same thing.
1.)
char *ptr = malloc(5);
ptr = "hi";
2.)
char *ptr = "hi";
I would want to know the difference between the two like if there any advantages of one over the other.
The former is a bug, and that code should never have been written.
It overwrites the pointer returned by malloc() with the address of a string literal, dropping the original pointer and leaking memory.
You must use strcpy() or some other memory-copying method to initialize newly allocated heap memory with a string.
The second just assigns the (run-time constant) address of the string literal to the pointer ptr, no characters are copied anywhere.
The first bit is a possible memory leak, the second relies on the implicit const storage class being used, and assigns the memory address of an immutable string to a pointer.
Basically:
char *ptr = malloc(5);//allocates 5 * sizeof *ptr
//then assigns the address where this block starts to ptr
//this:
ptr = "hi";//assigns position of 'h','i', '\0' in read-only mem to ptr
Now, the address you've allocated, that ptr pointed to, still is allocated. The difference is that you have no "handle" on it anymore, because ptr's value changed. There's no pointer pointing to the dynamic memory you allocated using malloc, so it's getting rather tricky to manage the memory... You probably won't be able to free it, and calling free on ptr now will result in undefined behaviour.
If you write:
char *ptr = "hi";
Then you're actually writing:
const char *ptr = "hi";
Which means you can't change the string to which ptr points:
ptr[0] = 'H';//IMBOSSIBRU
Alternatives are:
char string[] = "Hi";//copies Hi\0 to string
//or
char *ptr = malloc(5);
strcpy(ptr, "hi");//requires string.h
The difference between the two snippets above is that the first creates a stack array, the second allocates a block of memory on the heap. Stack memory is easier to manage, faster and just better in almost every way, apart from it being less abundant, and not really usable as a return value...
There is a pool of string literals for every process. Whenever you create a string literal inside your code, the literal is saved in the pool and the string's address (i.e. an address pointing somewhere to the pool) is returned. Therefore, you are creating a memory leak in your first option, because you are overwriting the address you received with malloc.
In the first case
char *ptr = malloc(5);
ptr = "hi";
There is a memory leak and later you are pointing ptr to a string literal "hi" which does require any memory from the heap (that's why there is memory leak).
But if you are allocating the memory and if you are using
strcpy (ptr, "hi");
then if you wish you can modify it
strcpy (ptr, "hello")
with one condition that you allocate sufficient memory before.
But in your case you are assigning a pointer ptr with a string literal, here you will not be able to modify it
ptr = "hello" // not valid. This will give a segmentation fault error
In your second case there is no memory leak and you are making a pointer to point to a string literal and thus it's value cannot be modified as it will be stored in read only data segment.

Why this code giving run time exception when free-ing the pointer

I have simple code,
#include "stdafx.h"
#include <malloc.h>
int main()
{
char *p = (char*) malloc(10);
p = "Hello";
free(p);
return 0;
}
This code is giving run time exception while terminating. Below is error snippiest,
Microsoft Visual C++ Debug Library
Debug Assertion Failed!
Program: ...\my documents\visual studio 2010\Projects\samC\Debug\samC.exe
File: f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
Line: 1322
Expression: _CrtIsValidHeapPointer(pUserData)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
Abort Retry Ignore
p = "Hello"; makes p point to a string literal and discards the previously assigned value. You can't free a string literal. You can't modify it.
If you want p to hold that string, just use
char* p = "Hello";
or
char p[] = "Hello";
if you plan on modifying it.
Neither requires free.
This is how you write a string in the memory allocated by malloc to a char pointer.
strcpy(p, "Hello");
Replace the line
p = "Hello";
with the strcpy one & your program will work fine.
You also need to
#include <string.h>
malloc returns a pointer to allocated memory. Say the address is 95000 (just a random number I pulled out).
So after the malloc - p will hold the address 95000
The p containing 95000 is the memory address which needs to be passed to free when you are done with the memory.
However, the next line p = "Hello"; puts the address of the string literal "Hello" (which say exists at address 25000) into p.
So when you execute free(p) you are trying to free 25000 which wasn't not allocated by malloc.
OTOH, when you strcpy, you copy the string "Hello" into the address starting at p (i.e. 95000). p remains 95000 after the strcpy.
And free(p) frees the right memory.
You can also avoid the malloc and use
char *p = "Hello";
However, in this method, you cannot modify the string.
i.e. if after this you do *p = 'B' to change the string to Bello, it becomes an undefined operation. This is not the case in the malloc way.
If instead, you use
char p[] = "Hello";
or
char p[10] = "Hello";
you get a modifiable string which need not be freed.
p = "Hello";
free(p);
Since Hello is statically allocated, you cannot free it. I'm not sure why you allocate some memory just to throw the pointer away by changing it to another pointer, but that has no effect. If you do this:
int i = 1;
i = 2;
i has no memory that it once held a 1, it holds a 2 now. Similarly, p has no memory that it once held a pointer to some memory you allocated. It holds a pointer to an immutable constant now.
this is a nice one.
the char sequence "hello" is constant and therefore placed niether on the heap nor the stack, but in the .bss/.data segment. when you do p="hello" you make p point to the address of the string hello in that segment instead of the memory you alocated on the heap using malloc. when you go to free p it tries to free the memory in the .bss/.data segment, and naturally fails.
what you probably want is something like strcpy(p,"hello"); which goes over every char in "hello" and places it in the memory pointed to by p. essentially creating a copy of the string "hello" at memory address p.
If you want to copy the contents of the string "Hello" to the memory you allocated, you need to use strcpy:
strcpy(p, "Hello");
The line
p = "Hello";
assigns the address of the string literal "Hello" to the pointer p, overwriting the pointer value that was returned from malloc, hence the crash when you call free.

Why does strcpy fail with char *s but not with char s[1024]?

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.

Resources