Memory allocated in char * var; declaration - c

In C, declaring a char pointer like this
char* p="Hello";
allocates some memory for a string literal Hello\0. When I do this afterwards
p="FTW";
what happens to the memory allocated to Hello\0? Is the address p points to changed?

There is no dynamic memory allocation in either statement.
Those strings are stored in your executable, loaded in a (likely read-only) section of memory that will live as long as your process does.
The second assignment only changes what p points to. Nothing else happens.

The memory remains occupied by "Hello". It is lost (unless you have other references to it).
The address p is pointing to (the value of p) is changed of course.

In this case, "Hello" is created at compile time and is part of the binary. In most situation "Hello" is stored in read only memory. "FTW" is also part of the binary. Second assignment will only change the pointer.

in addition - "Hello" and "FTW" have static storge duration as Met have pointed out

It creates a string constant that cannot be modified and should be used as it is.
If you try doing
p[0]='m';
It would give segmentation fault since this is not string literal with allocated memory in which you can reassign and read back values.

what if
p = getbuffer();
getbuffer()
{
return buf = malloc(buf, size);
}
how can free this memory before allocating new memory to p! imagine that p should use getbuffer() many times.

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.

what happen to memory assigned to a string addressed by a pointer when that pointer points to a new string?

char *p = "hello";
p = "hello_2";
Here string "hello" was stored in memory and its address was present in pointer 'p' but when this pointer starts pointing to string "hello_2", what will happen to the memory where the string "hello" was stored? Will it be freed or this string remains there but we can't access it?
What you have is a string constant and it is stored in read-only memory.
So this memory is not required to be freed explicitly using free()
Till the lifetime of the variable p is valid you can access the stored string.
The memory will not be freed. But would not (in this case), be lost. The code knows where the string is, and uses it each time the fragment is run, to assign to the pointer p.
Memory which is on the heap does need to be freed (result of malloc or strdup).
Memory which is on the stack does not need to be freed.
Memory which is static (this case) does not need to be freed.
You are actually creating a string literal named "hello" allocating it somewhere in the memory , and assigning the address of first character of the literal to the pointer p, and as the pointer is not constant you can assign it again with different addresses. And one more important point to note is that the string literal created are in read only memory.
There are different memory sections to which the globals, heap, code and string literals go to. It is specific to the compiler used.
gcc makes a .rodata section which is a read-only section and the string literals are stored there.
Visual C++ creates a .rdata section for the read only section.
You can use objdump (on linux) to check different sections for your binary.

Assignments to malloced string behaving wierd

Here are the codes, it's C code. And please explain return value of ="string"
char * p = (char*) malloc(sizeof(char) * 100);
p = "hello";
*(p+1) = '1';
printf("%s", p);
free(p);
Notice that p = "hello"; does not copy any string, but just sets the pointer p to become the address of the 6 bytes literal string "hello". To copy a string use strncpy or strcpy (read strncpy(3) ...) but be scared of buffer overflows.
So you do
char * p = malloc(100);
which allocates a memory zone capable of holding 100 bytes. Let's pretend that malloc succeeded (read malloc(3)...) and returned the address 0x123456 for example (often, that concrete address is not reproducible from one run to the next, e.g. because of ASLR).
Then you assign p = "hello"; so you forgot the address 0x123456 (you've got now a memory leak), and you put in p the address of the 6 bytes literal string "hello" (let's imagine it is 0x2468a).
Later the machine executes the code for *(p+1) = '1'; so you are trying to replace the e character (at address 0x2468b) inside literal "hello" by 1. You get a segmentation violation (or some other undefined behavior), since that literal string sits in constant read only memory (e.g. the text segment of your executable, at least on Linux).
A better code might be:
#define MY_BUFFER_LEN 100
char *p = malloc(MY_BUFFER_LEN);
if (!p) { perror("malloc for p"); exit(EXIT_FAILURE); };
strncpy(p, "hello", MY_BUFFER_LEN); /// you could do strcpy(p, "hello")
*(p+1) = '1';
printf("%s", p);
free(p);
and if you are lucky (no memory failure) that would much later output h1llo (the output will happen only when stdout becomes flushed since it is buffered, e.g. by some later call to fflush). So don't forget to call
fflush(NULL);
after the previous code chunk. Read perror(3), fflush(3).
A generic advice is to read documentation of every function that you are using (even printf(3) ...).
Regarding printf and related functions, since stdout is often line buffered, in practice I strongly recommend to end every format control string with \n -e.g. printf("%s\n", p); in your code; when you don't do that (there are some cases where you don't want to...) think twice and perhaps comment your code.
Don't forget to compile with all warnings and debug info (e.g. gcc -Wall -Wextra -g) then learn how to use the debugger (e.g. gdb)
Your code doesn't do what you think it does.
"hello" is behind the scenes a pointer to a static array of six chars, most likely write protected.
When you assign it to p, the pointer that malloc returned is lost, instead p now contains a pointer to that static array of six chars.
The assigment to p+1 may crash, or may not crash, but whatever it does, it is undefined behaviour and will cause trouble.
free (p) tries to free a static array of six chars. That isn't going to work. Again, undefined behaviour, and an immediate crash if you are lucky.
There are problems in nearly each line:
1) In the first line you are assigning to p the address of newly allocated memory. which is OK
2) In the next line you overwrite it with an address of some static string. Which is bad, since the allocated memory is "lost", thus causing memory leak.
3) In the third line you are trying to overwrite something in the static string location, which might be read only, which is bad.
4) In the last line you are trying to free the memory at the string's location, which is memory violation.
You need to understand what pointers are.
In C, there is no variable that can store a string. Instead the strings are stored in arrays of chars. In order to be able to handle such an array, you use a variable (called pointer) that stores the memory address of the first element of the array. Also, strings have a special character (the nul character) the indicate where they end, but that's not relevant here.
In the code you posted, you allocate memory to store 100 chars (this is usually 100 bytes) and get a pointer to the first element of this memory region, called p (for further reading: Do I cast the result of malloc?).
Whenever you use a string literal, some memory gets allocated and it gets stored in that memory region. When you assign it to p, p now points to the first element of the new memory region, that stores the string (so you've lost the memory allocated you malloc -> memory leak). Now, you try to modify the string pointed at by p. This won't work, as the string literals are stored as constant strings. And after that, you try to free the memory of this string, which is not possible. All of these mistakes generate runtime errors and are not very easy to detect and fix. In order to be able to achieve what you want, use a function like strcpy to copy the string from the read-only memory region to your pointer:
strcpy(p, "string");
Strings in C are arrays, and you can't use = to assign values to arrays, only to indexed elements of arrays. For copying string data, use strcpy() or strncpy(). Your code could look like:
char *p = (char*) malloc(sizeof(char) * 100);
strcpy(p, "hello");
*(p+1) = '1';
printf("%s", p);
free(p);
Try that. The difference is that p = "hello" will set the pointer p to point to the constant string "hello", overwriting the pointer to the 100-byte memory block you just allocated. The free(p); call below will fail because you're passing a pointer not returned by an allocation function, even if the system you're using doesn't give a write fault on attempting to modify constant data.
If you ever do need to point a pointer at a constant string (it happens), be sure you declare the pointer as const char *. This is required in C++. I don't know if it's required in newer versions of C, but it's a Real Good Idea in any case.
1) In C it is incorrect cast the return of malloc() (C++, okay to cast)
2) Once allocated memory, assigning a value to p is not done by =.
strcpy(p, "hello"); is better.
3) Once assigned correctly, using strcpy(), *(p+1) = '1' is the same as p[1] = '1', and will result in "h1llo".
By the way, using the line *(p+1) = '1' AFTER using p = "hello" to assign the value hello (instead of strcpy()) will cause problems, as described by #gnasher, #Basile and others.

I feel confusion about bus error in string (C)

I feel confusion about the swap two characters in one string with C.
It works well when I set it as an array:
char strBase[8] = "acbdefg";
in this case I could swap any character.
But it trigger the bus error when I set it as a string:
char *strBase = "acbdefg";
Thanks a lot for anyone could explain it or give me some hint!
The difference here is that
char *strBase = "acbdefg";
will place acbdefg in the read-only parts of the memory and making strBase a pointer to that, making any writing operation on this memory illegal.
It has no name and has static storage duration (meaning that it lives for the entire life of the program); and
a variable of type pointer-to-char, called strBase, which is initialised with the location of the first character in that unnamed, read-only array.
While doing:
char strBase[8] = "acbdefg";
puts the literal string in read-only memory and copies the string to newly allocated memory on the stack.
So this array is allocated in memory, and how long it lives for, depends on where the declaration appears. If the declaration is within a function, it will live until the end of the block that it is declared in, and almost certainly be allocated on the stack; if it's outside a function, it will probably be stored within an "initialized data segment" that is loaded from the executable file into write able memory when the program is run.
Making
strBase[0] = 'x';
legal.
Your problem is one of memory allocation. You need space to store your characters. When you wrote:
char strBase[8] = "acbdefg";
you created automatic storage (often called the stack) and initialized it with a string of characters. But when you wrote:
char *strBase = "acbdefg";
you created a pointer and pointed it at a constant string. The compiler puts that in a part of memory that is marked as read-only. If you try to change that it will result in a memory access violation.
Instead you could do something like:
const char* strData = "acbdefg";
int size = 1024;
char *strBase = (char*)malloc(size);
strncpy(strBase, strData, size);
ProcessString(strBase);
free(strBase);
The most likely cause is that
char strBase[8] = "abcdefg";
causes the compiler to reserve memory for an eight-character array, and initializes it with the value "abcdefg\0". In contrast,
char *strBase = "abcdefg";
only reserves memory for a pointer, initialized with the address of the string. "abcdefg" is a constant string, and as a result, the compiler stores it in a section of memory that gets marked read-only. Attempting to modify read-only memory causes a CPU fault.
Your compiler should be giving you a warning about const mismatch in the second case. Alternatively, your compiler may have a setting that changes the read-only-ness of constant strings.

Is malloc-ing a char the same as referencing a char array?

I think I have got my head mostly around the difference, but if I am correct, then this should be correct also:
1.)
char *string1 = (char*) malloc(runtime_determined_number);
2.)
char string2val[runtime_determined_number];
char *string2 = &string2val;
Here I would expect string1 and string2 to be the same, is this the case?
string1 and string2 are not pointed to the same memory area
string1 is a pointer pointing to a char array allocated dynamically with malloc
string2 is a pointer pointing to a char array allocated statically
They both point to uninitialized blocks of memory of the same length. So in that respect they are the same, yes.
Note that in case 1, you are responsible for freeing the memory once you're finished. And in case 2, you can't safely return the pointer from a function as the memory will go out of scope on exit.
Using malloc you are asking the OS for memory during runtime. If malloc succeeded you are able to work with the allocated memory. You must deallocate this memory later on!
In your second part you are creating a char-array and then assign its address to a pointer. In this case the memory is taken from the stack and will be freed automatically when the array goes out of scope.
Your char*s won't be the same as they will be pointing to different locations in memory. There is aminor chance they contain the same garbage as you have not initialized them...
They are similar in that they have the same type and have at least runtime_determined_number bytes allocated for them.
They are different in that:
the first version requires an explicit free() to avoid a memory leak;
the lifetime of the two objects may or may not be the same.
Note that the second version is only valid in C99, since it makes use of a variable-length array.

Resources