Malloc error - can't assign to variable sized object - c

For the malloc statement below, I am failing to initialize a variable-sized object
int textsize = BUF_SIZE;
char *lines[textsize] = malloc(sizeof(char *) * textsize);
The objective is to have an array of pointers where each will store the pointers to STDIN lines entered by the user.
textsize is the number of lines that is supported as input by the user.
Error:
error: variable-sized object may not be initialized
char *lines[textsize] = malloc(sizeof(char *) * textsize);

This is because you have allocated the lines with textsize as a size:- static, and then you are trying to allocate dynamically using malloc..
Try double pointer
char **lines = malloc(...)

As #A.Shenoy mentioned, you should use a double pointer. The reason for that is when you do char *lines[textsize], you're creating a pointer to a char array, but malloc returns a char pointer. So the solution is to do char **lines which creates a pointer to a char pointer. You still need to allocate space for the pointers, this is how you can initialize the array;
#define ARRAY_SIZE 5 // array of 5 strings
char **lines = (char**) malloc(sizeof(char*) * ARRAY_SIZE);
int i;
for (i = 0; i < ARRAY_SIZE; i++) {
lines[i] = (char*) malloc(sizeof(char) * textsize);
}
// The array is now allocated, and you can fill it with strcpy
// Example for filling:
char text[] = "Hello World!";
strcpy(lines[0], text);

Related

memcpy() not working as expected when copying pointers

I want to copy the content of a char **pointer to another pointer. My attempt was:
void test(char **arr, int len) {
printf("1: ");
printArr(arr, len);
char ***res = malloc(sizeof(char **));
res[0] = malloc(sizeof(char *) * len);
memcpy(&res[0], arr, len);
printArr(res[0], len);
Here I just wanted to copy the contents of arr, which holds several strings, to r[0] whereby len denotes the number of elements in arr. However, when inspecting res[0] I realised that it only stores two times null. As one can tell I'm a very beginner and have been learning C since a few days, so onc can expect simple mistakes.
char ***res = malloc(sizeof(char **));
res[0] = malloc(sizeof(char *) * len);
memcpy(&res[0], arr, len);
The first line allocates space for a single char ** and makes res point at it
The second line allocates space for an array of len pointers to char and makes res[0] point at it.
The third line copies len byes from arr over the top of the memory pointed at by res, overwriting the result of the second malloc call and then scribbling over memory after the block allocated by the first malloc call.
You probably actually want something like
mempy(res[0], arr, len * sizeof(char*));
which will copy an array of len pointers (pointed at by arr) into the memory allocated by the second malloc call.
If this is an array of C strings that you need deep copied:
char** array_deep_copy(char **arr, int len) {
// calloc() makes "allocation of N" calculations more clear
// that this is N allocations of char* becoming char**
char **res = calloc(len, sizeof(char*));
for (int i = 0; i < len; ++i) {
// Use strdup() if available
res[i] = strdup(arr[i]);
}
return res;
}
Note that this needs a proper release function that will go through and recursively free() those cloned strings or this leaks memory.
If you only need a shallow copy:
char** array_shallow_copy(char **arr, int len) {
char **res = calloc(len, sizeof(char*));
// memcpy(dest, src, size) is usually more efficient than a loop
memcpy(res, arr, sizeof(char*) * len);
return res;
}
This one doesn't need a recursive free(), you can just free() the top-level pointer and you're done. This one shares data with the original, so if any of those pointers are released before this structure is then you'll have invalid pointers in it. Be careful!

What does char **text = (char **) malloc(n * sizeof(char*)); does?

i just started with programming and i don't know what does this mean ..
I tried everything i could..
I know its dynamic memory allocation but don't know what all these (stars) means.
Could someone explain me, what every type is?
This is the code:
char **text = (char **) malloc(n * sizeof(char*));
text[i] = (char *) malloc(MAX_LENG);
The code allocates (dynamic) memory for holding n strings. Each of these strings with max length MAX_LENG - 1.
I assume the complete original code to be:
char **text = (char **) malloc(n * sizeof(char*));
for (int i = 0; i < n; ++i)
text[i] = (char *) malloc(MAX_LENG);
or without the unnecessary casts:
char **text = malloc(n * sizeof(char*));
for (int i = 0; i < n; ++i)
text[i] = malloc(MAX_LENG);
So the first line, i.e.
char **text = malloc(n * sizeof(char*));
will give you a pointer to a memory area holding n pointers-to-char
The loop, i.e.
for (int i = 0; i < n; ++i)
text[i] = malloc(MAX_LENG);
then makes each of these n pointers point to a memory area with MAX_LENG chars.
It looks like:
So after this you have memory for n strings and can use them like:
strcpy(text[0], "HELLO"); // First string is "Hello"
strcpy(text[1], "WORLD"); // Second string is "World"
After this it looks like:
You can access the individual charaters like this
char c = text[1][4]; // c now holds the character 'D' from the string "WORLD"
A simple explanation can look the following way. Let's assume that you have an array of pointers to string literals. For example
char * s[] = { "Hello ", "World!" };
The array designator used in expression with rare exception is converted to pointer to its first element. So the array designator s in most cases is converted to pointer of the type char **. That is it is a pointer to an object of the type char *.
For example
char **p = s;
Dereferencing the pointer you will get the first element of the array that in turn has the type char *. For example
#include <stdio.h>
int main( void )
{
enum { N = 2 };
char * s[N] = { "Hello ", "World!" };
for ( char **p = s; p != s + N; ++p )
{
printf( "%s", *p );
}
putchar( '\n' );
return 0;
}
The program output is
Hello World!
Now let's assume that you want to allocate the array s dynamically. The array has N element of the type char *.
So you need to write the expression
malloc( N * sizeof( char * ) )
The function call return pointer to the start of the allocated extent of memory where there will be the first element of the type char *. That is the function returns a pointer of the type void * to potentially the first element of the dynamically allocated array.
So you need to write
char **p = malloc( N * sizeof( char * ) );
or
char **p = ( char ** )malloc( N * sizeof( char * ) );
It is similar to the declaration shown above
char **p = s;
Other answers explained what it does but I want to focus on one small detail.
char **text = malloc(n * sizeof(char*));
Using the types instead of objects in sizeof is considered as a not good practice. Why? If you change the type of the object you need to change all possible appearances of the old type. If you use the object in the sizeof - every sizeof will be calculated correctly without any changes in the code.
char **text = malloc(n * sizeof(*text));

memory leak when concatenating strings into array

I have one function, alloc_str, which takes a string pointer and an array of pointers. It dynamically increases the size of the array by one and appends the string into the array. I have run a GDB debugger and highlighted my memory leak and const error below.
My expected input/output:
array = alloc_str(array, "test_1");
array = alloc_str(array, "test_2");
array = alloc_str(array, "test_3");
--> ["test_1", "test_2", "test_3"]
My alloc_str function:
char **alloc_str(char **existing, const char *add)
{
int length = 0; //find the length of the array
for (; existing[length]; length++)
{
}
//allocate memory to copy array array
char **existing_c = (char **)calloc(length + 2, sizeof(char *));
for (int i = 0; i < length; i++) //copy original array into new array
{
existing_c[i] = existing[i];
}
//possible memory leak error
strncat(existing_c, add, sizeof(existing_c) - strlen(existing_c) - 1);
existing_c[sizeof(existing_c)-1] = '\0';
//possible memory leak error
strncpy(existing, existing_c, sizeof(existing - 1));
s_copy[sizeof(destsize)-1] = '\0'; //error here
free(existing);
return existing_c;
}
void free_array(char **strings) //free's data in array, should be fine
{
int length = 0;
for (; strings[length]; length++)
{
}
strings = (char **)calloc(length + 2, sizeof(char *));
}
My main function:
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
int main(){ //should be fine
char **array = NULL;
char **test;
array = (char **)calloc(1, sizeof(char *)); //array has no strings yet
array = alloc_str(array, "test_1");
array = alloc_str(array, "test_2");
array = alloc_str(array, "test_3");
for (test = array; *test; test++)
{
printf("%s\n", *test);
}
free_array(array);
}
My error:
Subscript of pointer to function type 'void (const void *, void *, size_t)' (aka 'void (const void *, void *, unsigned long)')
There are multiple problems:
char **alloc_str(char **existing, const char *add)
{
int length = 0; //find the length of the array
for (; existing[length]; length++)
{
}
//allocate memory to copy array array
char **existing_c = (char **)calloc(length + 2, sizeof(char *));
for (int i = 0; i < length; i++) //copy original array into new array
{
existing_c[i] = existing[i];
}
////////////////////////////////////
//possible memory leak error
strncat(existing_c, add, sizeof(existing_c) - strlen(existing_c) - 1);
existing_c[sizeof(existing_c)-1] = '\0';
//possible memory leak error
strncpy(existing, existing_c, sizeof(existing - 1));
s_copy[sizeof(destsize)-1] = '\0'; //error here
////////////////////////////////////
free(existing);
return existing_c;
}
The part marked with //////////////////////////////////// does not make much sense.
You allocated an array of pointers. Don't treat it like a string. It is no string.
Instead simply assign the new pointer to the end of the array and add terminator again.
existing_c[length] = add;
existing_c[length+1] = NULL;
With that terminater you could use normal malloc instead of calloc because you assign all elements of the array anyway.
Besides the problem with allocation, you have another memory leak:
void free_array(char **strings) //free's data in array, should be fine
{
int length = 0;
for (; strings[length]; length++)
{
}
strings = (char **)calloc(length + 2, sizeof(char *));
}
You pass a pointer to an array of pointers. This array takes some memory that you allocated with calloc earlier.
Then you allocate a bit more memory and assign the address to local variable string.
This has two problems:
The memory that was allocated earlier is not freed.
The memory you allocate in this function is not accessible outside of that function.
In the end, your free_array function does not free anything but consumes more memory.
Another problem might be present with the strings that you store in that array.
In your example you use string literals. These are static objects and there is no need to free them.
If you will use your functions to store pointers to dynamically allocated string as well, you will need to take care about allocating and freeing the strings as well.
strncat() works on a memory buffer containing a NUL-terminated (aka "C") string:
char buf[10] = {'a', 'b', 'c', '\0'};
strncat(buf, "def", sizeof(buf) - strlen(buf) - 1);
assert(strcmp(buf, "abcdef") == 0); // buf now equals to "abcdef"
https://ideone.com/fWXk8C
(Well, the use of strlen() kinda killed the benefit of strncat() over good ol' strcat() but that's another story...)
So it's very different from what you want to do in your exercise. You actually don't need either of strncat() or strncpy().

String Arrays: Delete original array and then return copy

I am new with C and I am trying to understand allocating strings.
I am trying to create a function called adding_string. It takes in an array of zero or more strings that has a null in the final location. Next, it makes a shallow copy of the array that is + 1 location bigger, then appends a copy of the string str onto the array. Finally, it deletes the original array and returns the new copy
This is what I have so far:
char **adding_string(char **array, const char *str)
{
size_t num = strlen(str) + 1;
char *final= (char *)malloc(num);
strncpy(final, str, num);
free(array);
//The above code would create a copy of the string "str".
//Then it puts that into the array.
//Not sure if free(array); would be the right method
//Having issues with returning final too
return final;
}
In the main function, you would have something like:
char **array = NULL;
char **lines;
array = (char **)calloc(1, sizeof(char *));
array = adding_string(array, "help");
array = adding_string(array, "plz");
array = adding_string(array, "thanks");
for (lines = array; *lines; lines++)
{
printf("%s\n", *lines);
}
I'm not sure if free(array) would be the right method to use to delete the original array, and I'm having issues with returning the new copy.
When I try returning the new copy, I get:
warning: return from incompatible pointer type
which is because of:
return final;
Your adding_string makes no sense, you make a copy of str, free the memory
from array and return the new copy. The function should return a double pointer to char,
you are passing a single-pointer to char. All other values are lost, you are
leaking memory like crazy.
I'd rewrite your adding_string like this:
char **adding_string(char **array, const char *str)
{
char **tmp;
if(str == NULL)
return NULL;
// first make copy
size_t len = strlen(str);
char *strcopy = malloc(len+1);
if(strcopy == NULL)
return NULL;
// you've allocated enough memory for the copy
// no need of strncpy here
strcpy(strcopy, str);
// get the number of strings saved
size_t size = 0; // number of strings saved
if(array)
{
tmp = array;
while(*(tmp++))
size++;
}
// reallocate memory for array of strings
tmp = realloc(array, (size+2) * sizeof *tmp);
if(tmp == NULL)
{
// something went wrong, free the copy
free(strcopy);
return NULL;
}
tmp[size] = strcopy;
tmp[size+1] = NULL;
return tmp;
}
Note that in this version, if array is NULL, the function allocates the memory for the
array of strings. That's only a design choice, you could as well check that
array is not NULL and pass to adding_string a pre-allocated array of
strings. I think (and that's only my opinion) that is more elegant that
adding_string will create the first array. In this way, the code that
allocates memory is in one place only.
Now in your main
char **array = NULL;
char **lines;
// adding_string will allocate the memory for array when it's NULL
array = adding_string(array, "help");
array = adding_string(array, "plz");
array = adding_string(array, "thanks");
for (lines = array; *lines; lines++)
{
printf("%s\n", *lines);
}
Note that I do
tmp = realloc(array, (size+2) * sizeof *tmp);
size has the number of strings saved, that means that array
holds size+1 spaces, because the last one points to NULL. You are appending
one more strings, so you have to reallocate size+1+1 spaces, which is
size+2.
Please don't forget to free the memory afterwards.
The program below strictly follows your needs and intentions.
The array array is resized every time a new string is added. At the end of the program the proper cleanup of all allocated memory is done.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ** adding_string(char **array, const char *str)
{
size_t num = strlen(str) + 1;
char *final = (char *)malloc(num); // allocate memory for the string `str`
strncpy(final, str, num); // create the copy of the `str`
int i=0;
for(i=0; array[i] !=NULL; i++) {} // find how many elements do we have in the array
array[i] = final; // add final to the first empty spot in the `array`
i++;
char ** new_array = calloc(1+i, sizeof(char *)); // allocate a new array 1 size bigger
memcpy(new_array, array, sizeof(char*)*i); // copy all the pointers
free (array); // no need for the old array
return new_array; // return a pointer to the new bigger array
}
int main(void)
{
char **array = NULL;
char **lines;
array = (char **)calloc(1, sizeof(char *)); // allocate array for 4 poiters if type (char *)
array = adding_string(array, "help");
array = adding_string(array, "plz");
array = adding_string(array, "thanks");
for (lines = array; *lines; lines++)
{
printf("%s\n", *lines);
free(*lines);
}
free (array);
return 0;
}
Output:
help
plz
thanks
This is different approach where
char *adding_string(const char *str)
returns a pointer (char *) to the copy of the string. The array has already preallocated memory to accommodate all string pointers.
A small program to demonstrate the concept:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *adding_string(const char *str)
{
size_t num = strlen(str) + 1;
char *final= (char *)malloc(num); // allocate memory for the string str
strncpy(final, str, num); // crreate the copy
return final; // return a pointer to created copy
}
int main(void)
{
char **array = NULL;
array = (char **)calloc(4, sizeof(char *)); // allocate array for 4 pointers if type (char *)
array[0] = adding_string("help");
array[1] = adding_string("plz");
array[2] = adding_string("thanks");
for (int i=0; i<3; i++ )
{
printf("%s\n", array[i]);
free(array[i]);
}
free (array);
return 0;
}
Output:
help
plz
thanks

Assigning memory to double pointer?

I am having trouble understanding how to assign memory
to a double pointer.
I want to read an array of strings and store it.
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<20; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
instead of this I just assign a large block of memory and
store the string
char **ptr;
ptr = (char**)malloc(sizeof(char)*50*50);
would that be wrong? And if so why is it?
Your second example is wrong because each memory location conceptually would not hold a char* but rather a char. If you slightly change your thinking, it can help with this:
char *x; // Memory locations pointed to by x contain 'char'
char **y; // Memory locations pointed to by y contain 'char*'
x = (char*)malloc(sizeof(char) * 100); // 100 'char'
y = (char**)malloc(sizeof(char*) * 100); // 100 'char*'
// below is incorrect:
y = (char**)malloc(sizeof(char) * 50 * 50);
// 2500 'char' not 50 'char*' pointing to 50 'char'
Because of that, your first loop would be how you do in C an array of character arrays/pointers. Using a fixed block of memory for an array of character arrays is ok, but you would use a single char* rather than a char**, since you would not have any pointers in the memory, just chars.
char *x = calloc(50 * 50, sizeof(char));
for (ii = 0; ii < 50; ++ii) {
// Note that each string is just an OFFSET into the memory block
// You must be sensitive to this when using these 'strings'
char *str = &x[ii * 50];
}
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<50; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
fclose(fp);
may be your typo mistake but your loop should be of 50 instead of 20 if you are looking for 50 x 50 matrix. Also after allocation of memory mentioned above you can access the buffer as ptr[i][j] i.e in the 2D format.
A double pointer is just a pointer to another pointer. So you can allocate it like this:
char *realptr=(char*)malloc(1234);
char **ptr=&realptr;
You have to keep in mind where your pointer is stored at (in this example the double pointer points to a pointer variable on the stack so it's invalid after the function returns).
i will give one example, which might clear of the doubt,
char **str; // here its kind a equivalent to char *argv[]
str = (char **)malloc(sizeof(char *)*2) // here 2 indicates 2 (char*)
str[0]=(char *)malloc(sizeof(char)*10) // here 10 indicates 10 (char)
str[1]=(char *)malloc(sizeof(char)*10) // <same as above>
strcpy(str[0],"abcdefghij"); // 10 length character
strcpy(str[1],"xyzlmnopqr"); // 10 length character
cout<<str[0]<<endl; // to print the string in case of c++
cout<<str[1]<<endl; // to print the string in case of c++
or
printf("%s",str[0]);
printf("%s",str[1]);
//finally most important thing, dont't forget to free the allocated mem
free(str[0]);
free(str[1]);
free(str);
other simpler way to memorize
Case -1 :
step-1 : char *p;
step -2 :
please read it like below
char (*p); ==> p is a pointer to a char
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char) * some_len);
Case -2 :
step-1 : char **p;
step -2 :
please read it like below
char* (* p); ==> p is a pointer to a char *
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char *) * some_len);
Case -3 :
No one uses this but just for sake of explanation
char ***p;
read it as,
char** (*p); ==> p is a pointer to a char** (and for this check case-2 above)
p = malloc(sizeof(char**) * some_len);
Adding to Pent's answer, as he correctly pointed out, you will not be able to use this double pointer once the function returns, because it will point to a memory location on the function's activation record on stack which is now obsolete (once the function has returned). If you want to use this double pointer after the function has returned, you may do this:
char * realptr = (char *) malloc(1234);
char ** ptr = (char **) malloc(sizeof(char *));
*ptr = realptr;
return ptr;
The return type of the function must obviously be char ** for this.
well, this is how I do it:
#include <stdlib.h>
int main(void)
{
int i = -1; // just a counter
int j = 5; // how many strings
char *s[j];
while(++i < j)
s[i] = malloc(sizeof(char*)); // allocating avery string separately
return (0);
}
this also works:
char **allocate(int lines)
{
int i = -1;
char **s = malloc(sizeof(char *) * lines); // allocating lines
while (++i < lines)
{
s[i] = malloc(sizeof(char*)); // alicating line
scanf("%s", s[i]);
}
return (s);
}
int main(int ac, char *av[])
{
int lines = 5; // how many lines
char **s = allocate(lines);
return (0);
}
Double pointer is, simply put, a pointer to a pointer,
In many cases it is used as an array of other types.
For example, if you want to create an array of strings you can simply do:
char** stringArray = calloc(10, 40);
this will create an array of size 10, each element will be a string of length 40.
thus you can access this by stringArray[5] and get a string in the 6th position.
this is one usage, the others are as mentioned above, a pointer to a pointer, and can be allocated simply by:
char* str = (char*)malloc(40);
char** pointerToPointer = &str //Get the address of the str pointer, valid only in the current closure.
read more here:
good array tutorial

Resources