Dynamically allocating memory for 2d char array - c

I am using malloc to dynamically allocate a 2d char array. Unless I set every array index to NULL before free(), I get a segmentation fault when trying to free(). Why do I get a segmentation fault?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int nrows = 20; int ncolumns = 10;
char ** arr = malloc(nrows * sizeof(char *));
for(int i = 0; i < nrows; i++)
arr[i] = malloc(ncolumns * sizeof(char));
arr[0] = "string1";
arr[1] = "string2";
// does not work without the following code:
// for(int i = 0; i < 20; i++)
// arr[i] = NULL;
for(int i = 0; i < 20; i++)
free(arr[i]);
free(arr);
return 0;
}

When you do this:
arr[0] = "string1";
arr[1] = "string2";
You overwrite the contents of arr[0] and arr[1], which contain the addresses of memory returned from malloc, with the address of two string constants. This causes a memory leak, as that memory is no longer accessible. This is also the reason you crash when you call free because these variables no longer hold the addresses of allocated memory.
What you probably want to do here instead is use strcpy, which will copy the contents of the string literal to the memory you allocated.
strcpy(arr[0], "string1");
strcpy(arr[1], "string2");
Now you can free the memory properly.

Your code is ok, the problem comes from the fact that you are assigning string literals to your array here: arr[0] = "string1";.
You are thus replacing the pointer at arr[0], which is pointing to your allocated memory, with the pointer to a string literal.
Pointers to literals are protected, you cannot free (nor write to them) them because you didn't allocate them.
To solve this problem, use strcpy to copy the value of your literal inside your allocated memory:
strcpy(arr[0], "string1");
strcpy(arr[1], "string2");

= operator does not copy the string it only assigns the pointer. So your malloced memory is not accessible anymore for those array elements and attempt to free it is an Undefined Behavoiur which may lead to the segfault.
You need to copy it using strcpy.

Crashing upon a call to free is a sign of incorrect memory management somewhere else in your code. When you set a pointer to NULL then free it, you are not going to crash, because free(NULL) is guaranteed to be benign by the C Standard ยง 7.22.3.3:
7.22.3.3 The free function
...
If ptr is a null pointer, no action occurs. Otherwise, if
the argument does not match a pointer earlier returned by a memory management
function, or if the space has been deallocated by a call to free or realloc, the
behavior is undefined.
Emphasis mine.
As other answers have noted, you are trying to call free on memory that you didn't explicitly allocate with malloc-family functions (since you overwrote arr[i] pointers with pointers to string literals)

Two things to know:
You have two area in you memory (to make easy t understand) heap and stack
malloc, realloc, calloc allocate ressource from heap. I will say only malloc (but it is the same)
free can only free ressource from heap. Stack is reserver for the compiler (it store function call and other data)
The rule for each ressource you get from malloc you have to free it.
to free simply call the free function (but we can optionally assigne null pointer to be sure it is freed).
char * a = malloc(255);
to free
free(a);/* this is mandatory */
a = NULL;/* we can add this to the first line */
In fact it you take the habit to assign NULL value and one time you access it's value you will have NULL deference error: so you will know where to find error
What you try to do:
alloc a array char ** arr = malloc(nrows * sizeof(char *)); and you free it free(arr);
but you alloc 20 arrays of char arr[i] = malloc(ncolumns * sizeof(char));
you ignore it's value arr[0] = "string1"; (you loose the value returned by malloc so you can't free now arr[0]) we are not in C++. So "string1" is stocked on the stack (so malloc can't free it)
and you call free on it.
what you can do
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int nrows = 20; int ncolumns = 10;
char ** arr = malloc(nrows * sizeof(char *));
for(int i = 0; i < nrows; i++)
arr[i] = malloc(ncolumns * sizeof(char));
free(arr[0]);//know we can loose it value because it is freed
arr[0] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
free(arr[1]);//know we can loose it value because it is freed
arr[1] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
arr[0] = "string1";
arr[1] = "string2";
// does not work without the following code:
// for(int i = 0; i < 20; i++)
// arr[i] = NULL;
for(int i = 2; i < 20; i++)//we start at 2 because the first two value are on the stack
{
free(arr[i]);
arr[i] = NULL;//this is useless because we will free arr just after the loop)
}
free(arr);
arr = NULL;// this is useless because we exit the end of program
return 0;
}

Related

Explanation about types and variables used in a malloc code

I need some explanation for some commands in this particular piece of code:
#inlcude <stdlib.h>
#define PTRS 5
char *p[PTRS];
size_t nbytes = 10;
int i;
/* Allocating memory */
for (i=0; i<PTRS; i++){
printf("malloc of %10lu bytes ", nbytes);
if ((p[i] = (char *)malloc(nbytes)) == NULL){
printf("failed\n");
} else {
printf("succeeded\n");
nbytes *= 100;
}
/* Free the memory allocated */
for (i=0; i<PTRS; i++){
if(p[i]){
free(p[i]);
p[i] = NULL;
}
}
First one is
char *p[PTRS];
Does this line declare a pointer to an array or does it declare an array of pointers to char?
p[i] = (char *)malloc(nbytes) I understand that as i increases, p[i] will contain a pointer to the allocated memory called by malloc if it's successfully processed, and p[i] will beNULL` if no such memory can be prepared.
Second one is
if (p[i]){
free(p[i]);
p[i] = NULL;
}
This only frees memory if p[i] has any value (in this case a pointer to the memory). What happens if we remove if(p[i]) and only use free(p[i] and p[i] = NULL? Can we free a NULL pointer?
char *p[PTRS];
is equivalent to
char *(p[PTRS]);
i.e. it's an array of pointers, not a pointer to an array. A pointer to an array would be e.g.
char (*p)[PTRS];
The clockwise/spiral rule could be helpful in deciphering declarations. As would using resource such as https://cdecl.org.
And you can pass a NULL pointer to free (it's a no-op) so the check isn't needed really.
Depending on the further use of p, the p[i] = NULL assignment might not be needed either.
I understand that as i increases, p[i] will contain a pointer to the
allocated memory called by malloc
So if you understand this when it means that p[i] being an element of an array has the type char * because at least in the program there is explicit casting to this type of themalloc call in the if statement
if ((p[i] = (char *)malloc(nbytes)) == NULL){
So this declaration
char *p[PTRS];
declares an array of PTRS elements with the tyoe char *. I advice to write such a declarations like
char * p[PTRS];
inserting a blank after the character '*'.
You may rewrite the declaration also the following way
char * ( p[PTRS] );
A pointer to an array of PTRS elements of the type char is declared the following way.
char ( *p )[PTRS];
Can we free a NULL pointer?
More precisely it would be said may we use the function free with a null-pointer because we are not freeing a null pointer itself that in the context of your example has the automatic storage duration.
The answer is yes we may. A call of the function with a null pointer will have neither affect and is safe.
Thus this loop
for (i=0; i<PTRS; i++){
if(p[i]){
free(p[i]);
p[i] = NULL;
}
}
may be rewritten like
for (i=0; i<PTRS; i++){
free(p[i]);
p[i] = NULL;
}

Issue with free() on memory allocated for arrays

I'm working on learning how to properly deal with pointers, arrays etc in C. I'm a little confused on allocating the memory for them and then freeing that memory. The following is some test code I slapped together:
char *test[150000];
char **ptr;
for(int i = 0; i < 150000; i++)
{
test[i] = malloc(15*sizeof(char));
test[i] = "This is a test";
printf("test[%i] = %s located at %p\n",i,test[i],&test[i]);
}
for(int i=0; i < 150000; i++)
{
printf("Trying to free memory from %p\n",&test[i]);
ptr = &test[i];
free(ptr);
printf("Array item %i has been freed...",i);
}
The output yields the following:
[... Truncated]
test[149997] = This is a test located at 0x7fff581fbcc8
test[149998] = This is a test located at 0x7fff581fbcd0
test[149999] = This is a test located at 0x7fff581fbcd8
Trying to free memory from 0x7fff580d6d60
test2(17599,0x7fff7776f310) malloc: *** error for object 0x7fff580d6d60: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
sh-3.2#
It appears that when I try and free the pointer allocated, I get an error... Any ideas / pointers on where I'm screwing up would be greatly appreciated.
test[i] = malloc(15*sizeof(char));
This is ok, except that (a) it could be written as test[i] = malloc(15);, and (b) you don't check whether malloc succeeded.
test[i] = "This is a test";
This does not copy the contents of the string "This is a test" into the memory you just allocated. Rather, it's a pointer assignment, causing test[i] to point to the memory for the string literal. It creates a memory leak, since you no longer have a pointer to the memory you allocated with malloc. You probably want to use strcpy.
...
ptr = &test[i];
free(ptr);
Here you free the memory assigned to the string literal, not the memory you allocated.
Correction: that's not what it does. It tries to free the pointer object itself, which doesn't even make sense. (Incidentally, the argument to free doesn't have to be an object name; free(&test[i]) would be equally legal -- and equally incorrect.)
Assuming you fix the allocation problem, what you want is simply:
free(test[i]);
char *test[150000];
char **ptr;
for(int i = 0; i < 150000; i++)
{
test[i] = malloc(15*sizeof(char));
/*test[i] = "This is a test";*/ // Fix1
printf("test[%i] = %s located at %p\n",i,test[i],&test[i]);
}
for(int i=0; i < 150000; i++)
{
printf("Trying to free memory from %p\n",&test[i]);
/*ptr = &test[i];*/ //Fix2
free(test[i]); //Fix3
printf("Array item %i has been freed...",i);
}
Fix1:
Heap Memory is allocated and stored into test[i]. So test[i] has valid address. But again test[i] address is overridden using this statement test[i] = "This is a test"; If you want to copy the string into test[i] use strcpy.
Suppose if you like to assign like this test[i] = "This is a test"; do not allocate dynamic memory before this & no need to free also.
Fix2&Fix3:
The allocated address is stored in test[i] not in &test[i]. So just free that address present in test[i]. No need to use intermediate variable also. If required to use intermediate variable prefer to use char *ptr.

How to copy char *a[] to char **b?

Consider char *a[] = {"abc", "xyz", "def"};
Deep copy char *a[] to char **b.
Can someone say what is deep copy? And how much memory we need assign to b?
char *a[n];
Is an array of n pointers-to-char. Each element of the array is contiguous in memory. The size in memory required is
sizeof(char *) * n
I've used the sizeof() operator here... you could assume 4 bytes for a pointer but this might not be safe... this depends on your hardware.
char **b
Is slightly different. This is a pointer to a point-to-char. **b has not allocated the array of pointers. First allocate the array...
char **b = malloc( sizeof(char *) * n);
EDIT: Thank you to interjay for pointing out my mistake... example below now uses strdup() to allocate the memory for each b[i]
**b points to the start of an array of n pointers. For each pointer in that array you could so do b[0] = a[0] for shallow copies
This is a shallow copy because b[0] will point to the same memory that a[0] points to. Thus changing the contents b[0] will change the contents of a[0].
A deep copy would imply that you have two totally independent entities... so changing the contents b[0] would not result in a change to the contents of a[0]. This means that for each b[i] you need to allocate new memory and copy the string from a[i] into that new block.
To deep copy:
char *a[n];
// ...intialise array a....
char **b = malloc( sizeof(char *) * n); // allocate array of pointers
if( b )
{
int i = 0;
for(; i < n; ++i)
b[i] = (char *)strdup(a[i]); // allocate memory for new string and copy string
}
else
printf("You ran out of memory!\n");
As an asside...
You've used constant strings so you shouldn't technically modify them...
char *xxx = "String";
char yyy[] = "String";
You can safely modify the contents of yyy. Normally you can modify the contents of xxx without any problem, but note, because the string memory is allocated at compile time, you could find that the compiler has, for example, placed it in read only memory.
EDIT:
There seems to have been debate on whether to cast return from malloc (which I've been in the habit of doing, but it seems this was a bad habit!)... see Why do we need to cast what malloc returns?
Walking on the a array, for eah a[i] request space to alloc it by using one of *alloc() family functions and put the result in the respective b[i]. The b pointers itself shall be a pointer with enough space for hold the number of string in a as pointers. Compute with something like this:
int bsize = (sizeof(a)/sizeof(a[0])) * sizeof(char*);
char **b = malloc(bsize);
int i,len;
/* if(b == NULL) /* error: no memory */
for(i = 0,len = sizeof(a)/sizeof(a[0]); i < len; i++) {
char *tmp = malloc(strlen(a[i])+1);
if(tmp == NULL) /* error: no memory */
strcpy(tmp, a[i]);
b[i] = tmp;
}
Note that you need to or hold the size of b array in memory either put a NULL at end of array.
You can just do
b=a
This will assign base address of array of pointers *a[3] to b.
Now you can access strings using b
for example string 1 can be accessed by *(b+0) gives address of string 1
string 2 " " *(b+1) " " string 2
string 3 " " *(b+2) " " string 3
Since you are assigning array of pointers to pointer to a pointer you are already assigning memory to b Hence you do not need to use malloc.
Only when you are assigning some data to a pointer at run time and you have not assigned memory to pointer in your program then only use malloc.

How do I dynamically allocate an array of strings in C?

If I have the number of items in a var called "totalstrings" and a var called "string size" that is the string size of each item, how do I dynamically allocate an array called "array?"
This is an array of strings in C, not C++.
Thanks!
NOTE: My examples are not checking for NULL returns from malloc()... you really should do that though; you will crash if you try to use a NULL pointer.
First you have to create an array of char pointers, one for each string (char *):
char **array = malloc(totalstrings * sizeof(char *));
Next you need to allocate space for each string:
int i;
for (i = 0; i < totalstrings; ++i) {
array[i] = (char *)malloc(stringsize+1);
}
When you're done using the array, you must remember to free() each of the pointers you've allocated. That is, loop through the array calling free() on each of its elements, and finally free(array) as well.
The common idiom for allocating an N by M array of any type T is
T **a = malloc(N * sizeof *a);
if (a)
for (i = 0; i < N; i++)
a[i] = malloc(M * sizeof *a[i]);
As of the 1989 standard, you don't need to cast the result of malloc, and in fact doing so is considered bad practice (it can suppress a useful diagnostic if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope). Earlier versions of C had malloc return char *, so the cast was necessary, but the odds of you having to work with a pre-1989 compiler are pretty remote at this point. C++ does require the cast, but if you're writing C++ you should be using the new operator.
Secondly, note that I'm applying the sizeof operator to the object being allocated; the type of the expression *a is T *, and the type of *a[i] is T (where in your case, T == char). This way you don't have to worry about keeping the sizeof expression in sync with the type of the object being allocated. IOW, if you decide to use wchar instead of char, you only need to make that change in one place.
char** stringList = (char**)malloc(totalStrings * sizeof(char*));
for( i=0; i<totalStrings; i++ ) {
stringList[i] = (char*)malloc(stringSize[i]+1);
}
I know this question is old and was already answered. I just want to point out that malloc is a system call and shouldn't be used multiple times.
It would be better to allocate one big chunk of memory and make the array point to it. Something like this :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_SIZE 100 //STR_SIZE doesn't have to be a constant
int main(){
int i;
char **arr;
char *long_string;
long_string = (char *)malloc(sizeof(char)*STR_SIZE*10);
arr = malloc(sizeof(char *)*10);
//Pointing each item of the array to an allocated memory.
for (i=0; i<10; i++){
arr[i] = (long_string + STR_SIZE * i);
}
//Initialising the array
for (i=0; i<10; i++){
strcpy(arr[i], "This is a line in a\
paragraph\n");
}
//Printing the items of the array
for (i=0; i<10; i++){
printf("%s \n", arr[i]);
}
//freeing the allocated memory
free(long_string);
free(arr);
return 0;
}
Well, first you might want to allocate space for "array", which would be an array of char * that is "totalstrings" long.
What would then be the starting and final indexes in "array"? You know the first one is 0; what's the last one?
Then, for each entry in "array", you could (if you wanted) allocate one area of memory that is "stringsize+1" (why +1, pray tell me?) long, putting the starting address of that area -- that string -- into the correct member of "array."
That would be a good start, imo.

Array of pointers initialization

char **arr;
arr = (char **)calloc(1,sizeof(char*));
for(i = 0; i< 16; i++)
if(arr[i] = (char *)calloc(1, 2*sizeof(char)) == NULL)
perror("Memory cannot be allocated to arr[i]", %d);
The above code throws an error inside the for loop, when i am trying to allocate memory to arr[i]. Is anything wrong with this allocation. Essentially, i want to store 16 strings of length 2. I've tried it with array of pointers too (char *arr[16]). I have tried looking for resources on double pointer initializations using malloc() and calloc() and couldn't find many . If you could point out some links, that would be greatly appreciated.
Thanks.
You need to allocate enough memory for 16 pointers, not just one.
arr = (char **)calloc(16, sizeof(char*));
What happens with your code is that arr has enough memory only for one pointer, so arr[0] = <something> is correct, but arr[1] and higher is touching memory that doesn't belong to the program.
Additionally, the way you assign the string pointers is wrong. You are assigning 0 or 1 values, depending on whether the result if calloc is NULL. You need to add parentheses there:
if ((arr[i] = (char *)calloc(1, 2*sizeof(char))) == NULL)
perror("Memory cannot be allocated to arr[%d]", i);
Er even better:
for(i = 0; i < 16; i++) {
arr[i] = (char *)calloc(1, 2*sizeof(char));
if (arr[i] == NULL) {
perror("Memory cannot be allocated to arr[%d]", i);
}
}
When you use calloc, it is customary to use the first parameter to pass the number of elements in the array and the second parameter to pass the size of an element. So, to allocate an array of 16 pointers, one'd normally use calloc(16, <pointer size>), not calloc(1, 16 * <pointer size>), although both do the same thing. In your code you apparently completely forgot about 16 and allocated only 1 pointer.
Don't cast the result of 'calloc'.
Avoid using sizeof(<type>) when calculating size for memory allocation functions. Prefer to use sizeof *<pointer> instead.
If you want to store srings of length 2, you need a buffer of at least 3 characters long (an extra character for zero-terminator).
Memory allocation failure doesn't normally set errno, so perror is not an appropriate function to use here.
Yor assignment to arr[i] in if condition is missing braces. The operations are associated incorrectly. It won't compile as is.
char **arr;
arr = calloc(16, sizeof *arr);
for(i = 0; i < 16; i++)
if((arr[i] = calloc(3, sizeof *arr[i]) == NULL)
fprintf(stderr, "Memory cannot be allocated");
Finally, an unnamed "magic constant" (16 and 3) is most of the time not a good idea.
arr = (char **)calloc(1,sizeof(char*));
allocates one pointer to pointer to char.
Essentially, i want to store 16 strings of length 2
char **arr = calloc(16, sizeof *arr);
if (!arr) exit(-1); /* bail out somehow */
for(i = 0; i < 16; i++)
if((arr[i] = calloc(2, sizeof *arr[ i ])) == NULL)
printf("Memory cannot be allocated to arr[ %d ]", i + 1);
Check the parenthesization as well in your if condition and printf statement. Does your code even compile?
Storing two characters directly is less expensive than storing a pointer, so I'd suggest dropping one level of indirection and use a contigous block of memory:
char (*arr)[2] = calloc(16, sizeof *arr);
Also keep in mind that your character sequences can't be strings as you didn't provide memory for the terminating 0.

Resources