Reputation: 19
So I'm trying to modify data that I've allocated through malloc()
/calloc()
by using pointers...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char ** sentence = calloc(4, sizeof(char *));
sentence[0] = malloc(3);
sentence[0] = "the";
sentence[1] = malloc(5);
sentence[1] = "quick";
sentence[2] = malloc(5);
sentence[2] = "brown";
sentence[3] = malloc(3);
sentence[3] = "fox";
char *test = sentence[1] + 2;
printf("*test = %c\n", *test);
*test = 'a'; // This is where the error is occurring
printf("*test = %c\n", *test);
printf("sentence[1][2] = %c", sentence[1][2]);
return 0;
}
Valgrind is telling me that I have "bad permissions for mapped region".
I've also tried replacing sentence[1] + 2
with &(sentence[1][2])
, which yields the same results. I know that I can always do sentence[1][2] =
, but that's just in this dummy application. The target purpose is to be able to determine the address of a char (in alloc'ed memory, not [] array memory) at some point using indices, and then later on (once those indices have been lost), modify the char at that address. Is there any way to avoid this/achieve my target functionality?
Upvotes: 1
Views: 731
Reputation: 3872
There is a gap in (your) understanding of how an assignment works.
sentence[0] = malloc(3); // Allocates 3 bytes (subject to availability)
sentence[0] = "the"; // This makes sentence[0] point to a read-only, constant section in your memory map
sentence[1] = malloc(5); // Allocates 5 bytes (subject to availability)
sentence[1] = "quick"; // This makes sentence[1] point to a read-only, constant section in your memory map
sentence[2] = malloc(5); // Allocates 5 bytes (subject to availability)
sentence[2] = "brown"; // This makes sentence[2] point to a read-only, constant section in your memory map
sentence[3] = malloc(3); // Allocates 3 bytes (subject to availability)
sentence[3] = "fox"; // This makes sentence[3] point to a read-only, constant section in your memory map
So, all of above memory that you have malloc
ed, is leaked and lost.
Moreover, since all strings are read-only, any attempt to modify those will invoke Undefined Behaviour.
You can achieve what you are looking for this way:
if(sentence[0] != NULL)
{
sentence[0] = strdup("the");
}
else
{
// Handle the error here, that no memory was allocated
}
This will allow you to have a copy of "the" in an array that you can modify. Also note that to store "the"
you need 4 bytes, not 3. The one extra byte is to have '\0'
.
Finally, when you are done, before exiting de-allocate/free all the memory that you have allocated dynamically.
Upvotes: 1
Reputation: 83
"quick" is constant string (=mapped region).
for example,
sentence[1] = malloc(5); // if malloc returns 0x100, then 0x100 is assigned to sentence[1]
sentence[1] = "quick"; // assume that "quick"'s address is 0x200,
// so you assigned 0x200 to sentence[1] again.
// this means 0x100 will be lost and it causes memory leak.
So to avoid leak,
You should call strcpy()
instead of = "quick";
then 1*test = 'a';
will have no error.
You should alloc 1 more byte for '\0'
so that you can make it null-terminated string.
Upvotes: 3
Reputation: 7453
The line sentence[0] = malloc(3);
allocates three bytes of memory, and sets the pointer sentence[0]
to point to that memory. The next line, sentence[0] = "the";
, sets the pointer sentence[0]
to instead point to a static duration (permanently existing), constant, array of four char
s (including a '\0'
at the end!). At this point, sentence[0]
is completely unrelated to the three malloc
ed bytes on the previous line; those bytes are leaked memory, and the pointer points to somewhere completely different.
Presumably what you wanted to do is copy the contents of "the"
into newly-allocated memory. You can do that either by calling strdup
, which does both the allocation and copying, or with malloc
and strcpy
. If you go with the second method, remember that strings need one extra byte for the null termination.
Upvotes: 1
Reputation: 206667
Problem 1
All the lines of the form
sentence[0] = "the";
are wrong.
The memory allocated by the previous line, the return value of malloc
, is lost and is now a memory leak.
senctence[0]
points to some read-only parts of your program. Any attempt to modify those value will result in undefined behavior.
Problem 2
char *test = sentence[1] + 2;
*test = 'a';
is not right. sentence[1]
is a pointer to the read-only part of the program that holds "quick"
. test
points to the "ick"
of that string. However, that is still in the read-only part of the program. Trying to change anything in that memory is cause for undefined behavior.
Solution
You can use strdup
to get copies of the string that you can modify later.
sentence[0] = strdup("the");
Please note that strdup
is not a standard library function. However, you can find example implementations in many places on the web.
Deallocate Dynamically Allocated Memory
As a matter of good coding practice, deallocate any dynamically allocated memory in your program.
Upvotes: 3