Pointer to C style string isn't allocated - c

#include <stdio.h>
int main() {
char *t = "hello world";
puts(t);
//printf("%s", t);
t = "goodbye world";
puts(t);
}
The memory for t isn't allocated, so why I don't get segfault when I run it?

t is a pointer, so you are just making t point to another string.

Because string literals are allocated statically in your program memory - you do not need to allocate memory for them explicitly.

Memory is allocated for t; enough memory is allocated for it to hold a pointer (typically, 4 bytes in a 32-bit program, 8 bytes in a 64-bit program).
Further, the initialization for t ensures that the pointer points somewhere:
char *t = "hello world";
String literals are also allocated space, somewhere. Often, that is in the read-only portion of memory, so you should really be using const char *t = "hello world"; and even if you don't use the explicit const, you should not try to modify the string that t points at. But it is the compiler's problem to ensure that t is pointing somewhere valid.
Similarly, after the assignment:
t = "goodbye, Cruel World!";
the variable is pointing at space allocated by the compiler. As long as you don't abuse it (and your code doesn't), this is fine.
What would get you into trouble is something like this:
char *t;
puts(t); // t is uninitialized; undefined behaviour
t = 0; // equivalently, t = NULL;
puts(t); // t contains the null pointer; undefined behaviour
The uninitialized local variable could contain any value; you cannot predict reliably what will happen. On some machines, it may contain a null pointer and cause a crash, but that is not something you can rely on.
A null pointer doesn't point at anything valid, so dereferencing a null pointer leads to undefined behaviour, and very often that undefined behaviour is a crash. (Classically, on DEC VAX machines, you got a zero byte at address zero instead of a crash. That led (in part) to one of Henry Spencer's Ten Commandments "All the world is not a VAX" — and also "Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.")
So, in your program, memory is allocated for t and t is initialized and assigned to point to (read-only) string constants, so there is no excuse for the program to crash.

t is here a pointer to the first character of an anonymous string, which can be in read-only memory. A good idea is to declare the pointer as pointer to const char :
const char *t = "hello world";
See also here.

All the memory the compiler needs to allocate for t is 4 bytes on a 32-bit system. Remember that it's just a pointer. In the first couple of lines it's pointing to "hello world", but after that you change it so it points to "goodbye world". C will have allocated enough memory for the strings you have defined and passes you the pointer so you can point to them. You don't need to worry about that. Also remember that these string are static and read-only, which means you can't safely say t[4] = 'b';.

Related

What happens with memory when we reassign value to char pointer?

I wonder what happens inside the memory when we do something like this
char *s;
s = "Text";
s = "Another Text";
If I'm getting it right, by assigning string to char pointer memory is dynamically allocated. So according to my understanding assignment expression
s = "Text";
equals to
s = (char *) malloc(5); // "Text" + '\0'
strcpy(s, "Text");
Well, this way we can easily free memory by using
free(s);
But... After reassigning same pointer to another value, it allocates new memory segment to store that value.
s = "Text";
printf("\n(%p) s = \"%s\"", s, s);
s = "Another Text";
printf("\n(%p) s = \"%s\"", s, s);
Output:
(0x400614) s = "Text"
(0x400628) s = "Another Text"
That means that address of old value is not accessible to us any longer and we can't free that any more. Another call to free(s); will probably deallocate only last memory segment used by that pointer.
My question is: If we reassign same char pointer over and over again, does it consume more and more program memory during run-time or that garbage somehow gets automatically freed?
I hope that was enough to demonstrate my problem, couldn't think better example. If something's not clear enough please ask for additional clarification.
Your understanding is wrong. It is just the assignment and it does not allocate any memory. In your example you assign the pointer with the addresses of the string literals. String literals are created compile time and placed in the read only memory
You do now allocate any memory by assigning the pointer
It's not equal to doing a malloc. What's happening is that the string literal is stored in a read only part of memory. And it's not the assignment of a pointer that does the allocation. All string literals in a program are already allocated from start.
It might be worth mentioning that they are not strictly speaking stored in read only memory, but they might be and writing to a string literal is undefined behavior.
You cannot and should not call free on a string literal. Well, you can, but the program will likely crash.
With no optimization, compiler will reserve two distinct memory space for string literals "text1" and "text2".
If assignment lines are very consecutive as in your question and if nothing is done after the first assignment line —assuming compiling with optimization— compiler, most probably, will not allocate any space for the first string literal nor will produce any opcode for the first assignment line.

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";

strcpy behaving differently when two pointers are assigned strings in different ways

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 Segmentation fault in following code?

I read this on wikipedia
int main(void)
{
char *s = "hello world";
*s = 'H';
}
When the program containing this code is compiled, the string "hello world" is placed in the section of the program executable file marked as read-only; when loaded, the operating system places it with other strings and constant data in a read-only segment of memory. When executed, a variable, s, is set to point to the string's location, and an attempt is made to write an H character through the variable into the memory, causing a segmentation fault**
i don't know why the string is placed in read only segment.please someone could explain this.
String literals are stored in read-only memory, that's just how it works. Your code uses a pointer initialized to point at the memory where a string literal is stored, and thus you can't validly modify that memory.
To get a string in modifiable memory, do this:
char s[] = "hello world";
then you're fine, since now you're just using the constant string to initialize a non-constant array.
There is a big difference between:
char * s = "Hello world";
and
char s[] = "Hello world";
In the first case, s is a pointer to something that you can't change. It's stored in read-only memory (typically, in the code section of your application).
In the latter case, you allocate an array in read-write memory (typically plain RAM), that you can modify.
When you do: char *s = "hello world"; then s is a pointer that points to a memory that is in the code part, so you can't change it.
When you do: char s[] = "Hello World"; then s is an array of chars
that are on the stack, so you can change it.
If you don't want the string to be changed during the program, it is better to do: char
const *s = ....;. Then, when you try to change the string, your program will not crash with segmentation fault, it will arise a compiler error (which is much better).
first have a good understanding of pointers, I will give u a short demo:
First let us analyze your code line by line. Lets start from main onwards
char *s = "Some_string";
first of all, you are declaring a pointer to a char variable, now *s is a address in memory, and C will kick you if you try to change its memory value, thats illegal, so u better declare a character array, then assign s to its address, then change s.
Hope you get, it. For further reference and detailed understanding, refer KN King: C programming A Modern Approach
Per the language definition, string literals have to be stored in such a way that their lifetime extends over the lifetime of the program, and that they are visible over the entire program.
Exactly what this means in terms of where the string gets stored is up to the implementation; the language definition does not mandate that string literals are stored in read-only memory, and not all implementations do so. It only says that attempting to modify the contents of a string literal results in undefined behavior, meaning the implementation is free to do whatever it wants.

C string declaration

I am confused about some basics in C string declaration. I tried out the following code and I noticed some difference:
char* foo(){
char* str1="string";
char str2[7]="string";
char* str3=(char)malloc(sizeof(char)*7);
return str1;
/* OR: return str2; */
/* OR: return str3; */
}
void main() {
printf("%s",foo());
return 0;
}
I made foo() return str1/2/3 one at a time, and tried to print the result in the main. str2 returned something weird, but str1 and str3 returned the actual "string".
1.Now, what's the difference between the three declarations? I think the reason why str2 didn't work is because it is declared as a local variable, is that correct?
2.Then what about str1? If the result remains after the foo() ended, wouldn't that cause memory leak?
3.I'm simply trying to write a function that returns a string in C, and use the value returned by that function for other stuff, which str declaration above should I use?
Thanks in advance!
char* str1="string";
This makes str1 a pointer; it points to the first character of the string literal. You should define it as const, because you're not allowed to modify a string literal:
const char *str1 = "string";
...
char str2[7]="string";
This makes str2 an array of char (not a pointer), and copies the contents of the string literal into it. There's no need to define it as const; the array itself is writable. You can also omit the size and let it be determined by the initializer:
char str2[] = "string";
Then sizeof str2 == 7 (6 bytes for "string" plus 1 for the terminating '\0').
This:
char* str3=(char)malloc(sizeof(char)*7);
is written incorrectly, and it shouldn't even compile; at the very least, you should have gotten a warning from your compiler. You're casting the result of malloc() to type char. You should be converting it to char*:
char *str3 = (char*)malloc(sizeof(char) * 7);
But the cast is unnecessary, and can mask errors in some cases; see question 7.7 and following in the comp.lang.c FAQ:
char *str3 = malloc(sizeof(char) * 7);
But sizeof(char) is 1 by definition, so you can just write:
char *str3 = malloc(7);
malloc() allocates memory, but it doesn't initialize it, so if you try to print the string that str3 points to, you'll get garbage -- or even a run-time crash if the allocated space doesn't happen to contain a terminating null character '\0'. You can initialize it with strcpy(), for example:
char *str3 = malloc(7);
if (str3 == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(str3, "string");
You have to be very careful that the data you're copying is no bigger than the allocated space. (No, `strncpy() is not the answer to this problem.)
void main() is incorrect; it should be int main(void). If your textbook told you to use void main() find a better textbook; its author doesn't know C very well.
And you need appropriate #include directives for any library functions you're using: <stdio.h> for printf(), <stdlib.h> for exit() and malloc(), and <string.h> for strcpy(). The documentation for each function should tell you which header to include.
I know this is a lot to absorb; don't expect to understand it all right away.
I mentioned the comp.lang.c FAQ; it's an excellent resource, particularly section 6, which discusses arrays and pointers and the often confusing relationship between them.
As for your question 3, how to return a string from a C function, that turns out to be surprisingly complicated because of the way C does memory allocation (basically it leaves to to manage it yourself). You can't safely return a pointer to a local variable, because the variable ceases to exist when the function returns, leaving the caller with a dangling pointer, so returning your str2 is dangerous. Returning a string literal is ok, since that corresponds to an anonymous array that exists for the entire execution of your program. You can declare an array with static and return a pointer to it, or you can use malloc() (which is the most flexible approach, but it means the caller needs to free() the memory), or you can require the caller to pass in a pointer to a buffer into which your function will copy the result.
Some languages let you build a string value and simply return it from a function. C, as you're now discovering, is not one of those languages.
char* str1="string";
This creates a pointer to a literal string that will be located on either .data or .text segments and is accessible at all times. Whenever you do something like that, be sure to declare it const, because if you try to modify it, nasty things might happen.
char str2[7]="string";
This creates a local buffer on the stack with a copy of the literal string. It becomes unavailable once the function returns. That explains the weird result you're getting.
char* str3=(char)malloc(sizeof(char)*7);
This creates a buffer on the heap (uninitialized) that will be available until you free it. And free it you must, or you will get a memory leak.
The string literal "string" is stored as a 7-element array of char with static extent, meaning that the memory for it is allocated at program startup and held until the program terminates.
The declaration
char *str1 = "string";
assigns the address of the string literal to str1. Even though the variable str1 ceases to exist when the function exits, its value (the address of the literal "string") is still valid outside of the function.
The declaration
char str2[7] = "string";
declares str2 as an array of char, and copies the contents of the string literal to it. When the function exits, str2 ceases to exist, and its contents are no longer meaningful.
The declaration
char *str3 = (char*) malloc(sizeof(char) * 7);
which can be simplified to
char *str3 = malloc(sizeof *str3 * 7);
allocates an uninitialized 7-byte block of memory and copies its address to str3. When the function exits, the variable str3 ceases to exist, but the memory it points to is still allocated. As written, this is a memory leak, because you don't preserve the value of the pointer in the calling code. Note that, since you don't copy anything to this block, the output in main will be random.
Also, unless your compiler documentation explicitly lists void main() as a legal signature for the main function, use int main(void) instead.

Resources