Memory allocation for a char ** pointer in C - c

I have to maintain an array of strings, which each string will contain the IP address of a neighbor. For some reason i need to maintain them as strings.
typedef struct _neighbors
{
int num_neigbors;
char **neighbor_address;
} neighbors;
Assume i have two neighbors to add.
I view char ** neighbor_address as an array of char * pointers.
I understand that i need to malloc memory for neighbor_address[0] and neighbor_address[1] to store their IP addresses. Since the IP address is of form "x.y.z.w" i will be doing a malloc of 7*sizeof (char).
My doubt is how much memory should i allocate for the base char **neighbor_address. Should it be 4 bytes so that it can store the IP address of the base pointer of neighbor_address[0]?
I say this because i get a SIGSEGV (Segmentation fault) if i don't do a malloc as follows:
neighbor_address = malloc (1, sizeof (char *));
Anything that i am missing?

You should not do malloc like this-
neighbor_address = malloc (1, sizeof (char *));
you are not following the syntax of malloc here. It is the syntax of calloc. If you are using calloc you can use this method-
neighbor_address = calloc (n, sizeof (char *));
If you want to use malloc Try the following changes-
neighbor_address = (char **)malloc (n * sizeof (char *));
for(i=0;i<n;i++)
neighbor_address[i] = (char *)malloc (8 * sizeof (char));
But You are using structure here. So you need to use arrow operator to allocate memory for char **neighbor_address; because it is a pointer type. Try this-
neighbors -> neighbor_address = (char **)malloc (n * sizeof (char *)); // n -> no of ip addresses
for(i=0;i<n;i++)
neighbors -> neighbor_address[i] = (char *)malloc (8 * sizeof (char));

Oh, I think you didn't understand the max length of an IP Address.
It could be 3 digits between every dot so it can be 255.255.255.255 at maximum.
So the code to dynamically allocate memory for it would be so:
#define MAX_IP strlen("255.255.255.255")
int i;
neighbors my_neighbors;
my_neighbors.num_neighbors = ?; //Some value that is the num of IP Addresses needed to be stored.
my_neighbors.neighbor_address = malloc(sizeof(char*)*my_neighbors.num_neighbors); //allocate a char* (that is about to be a string) for each neighbor.
for(i = 0 ; i < my_neighbors.num_neighbors ; i++)
{
my_neighbors.neighbor_address[i] = malloc(sizeof(char)*(MAX_IP+1)); //Allocating enough room in each IP string for 255.255.255.255 + '\0' (null).
}
//Doing some stuff.
//Freeing memory:
for(i = 0 ; i < my_neighbors.num_neighbors ; i++)
{
free(my_neighbors.neighbor_address[i]);
}
free(my_neighbors.neighbor_address);
And that's it.
Hope you understood.

You can allocate the memory like this.
neighbor_address = (char**)malloc(num_neighbors * sizeof(char*));
for(i=0; i<num_neighbors; ++i) {
neighbor_address[i] = (char*)malloc(len_of_address);
}
Make sure that 'len_of_address' is large enough to store all characters (including the terminating '\0' character if you plan to store \0-terminated strings).
Be aware of the fact that you need more space than 1 character per fragment of the ip address if it is a number larger than 9.
So to store 196.168.0.3 you would need at least 12 characters.

First, two things: sizeof(char) is 1, regardless of the implementation. And I think you misunderstood malloc prototype. It takes the number of bytes you want to allocate, and it returns the allocated pointer.
If you want to store x IPs, then you'll have to do:
neighbor_address = malloc(x * sizeof(char*));
And then if you want to store 7 chars in each string, you'll have to do:
for (i = 0; i < x; i++)
neighbor_adress[i] = malloc(7 + 1); // 7 chars plus '\0' character

You must allocate memory for an array of num_neighbors char pointers. But most of all, remember to # include <stdlib.h> : you called malloc with wrong parameters, and that's probably what caused the segfault before a wrong size.
The least error-prone pattern for using malloc is this one :
neighbor_address = malloc(num_neighbors * sizeof *neighbor_address);
Just put the same variable as left operand of = and operand of sizeof, and adjust the number of elements.

Related

Realloc with matrix and automatization

I was wondering why realloc for a char* or whatever 1D array works if I do something like
oldpointer=realloc(oldpointer,newsize);
But when I try with a 2D char* array it fails.
Looking here and there I see that sometimes people use
NewPointer=realloc(oldpointer,newsize) but if it's the only use it will not be useful to me, since I need to resize the matrix' columns and rows often, in a loop (I must fill an array of strings without knowing first how many string I will insert nor the size of each one)
the code I used for trying is this,
void main(){
int max = 5, i,j;
char **matrix;
matrix=malloc(max*sizeof(char));
for(i=0;i<max;i++){
matrix[i]=malloc(max*sizeof(char));
}
matrix=realloc(matrix,max*2*sizeof(char));
strcpy(matrix[4],"we\0");
printf("%s",matrix[4]);
}
Error in `./out': realloc(): invalid next size: 0x00000000015c4010 ***
Aborted
The problem is that your double pointer can't hold pointers because you did not allocate enough space.
matrix = malloc(max * sizeof(char));
/* which is exactly the same as
* matrix = malloc(max);
*/
should be
matrix = malloc(max * sizeof(char *));
/* ^ max pointers, so sizeof a poitner */
then if you want to realloc(), you can do it like this
void *pointer;
pointer = realloc(matrix, 2 * max * sizeof(char *));
if (poitner == NULL)
handleFailure_OrExit_ButDoNot_Use_The_Realloced_Poitner();
matrix = pointer;
Always check the return value of a function if it returns one, for example malloc()/calloc()/realloc() "and any custom implementation normally", return NULL on failure.
First your matrix is an array of char*, so you should be allocating:
matrix=malloc(max * sizeof(char*));
Likewise for the realloc().
You also don't need "we\0", "we" would suffice. All strings in double quotes are NUL terminating string literals. Allocate enough memory for each of char*s and the chars and you should be good.

Need help creating a dynamic char array in C

I'm having trouble creating a dynamic char array. This is what I have so far.
char * arr;
arr = (char*)malloc (2 * sizeof (char));
It's not allocating space for only 2 characters, it's letting me enter up to arr[8] and then giving me strange errors after 8.
I also tried making a 2 dimensional char array. The first dimension allocates correctly, but then the second dimension has more space than I allow it to have and gets an error at around 12 characters or so. Any help would be greatly appreciated. I would prefer to make a 1 dimensional dynamic array if possible.
This line arr = (char*)malloc (2 * sizeof (char)); will allocate memory for 2 bytes only. But you are overwriting the memory by accessing the more 8 or more than 8 byes. If you access more than two byes means, it will give some unpredictable issue. In case you want more memory please follow the below code.
#define USER_SIZE 10
arr = (char*)malloc ( USER_SIZE * sizeof (char));
Assign the value in USER_SIZE macro and then allocate the memory as much as you want.
Example for 2D pointer ( 5 X 10 )
#define ROW 5
#define COLUMN 10
main()
{
unsigned char **p = NULL, colum = 0;
p = malloc ( ROW * sizeof ( unsigned char *) );
for (;colum< ROW; ++colum )
{
p[colum] = malloc (COLUMN * sizeof (unsigned char ));
}
}
What you are doing is called buffer overflow by writing beyond the bounds of memory allocated by malloc call. The compiler doesn't do bounds checking (it assumes you know what you are doing, and you only pay for what you use) and allow you to compile and run. However, it will lead to undefined behaviour and your program may crash. You shouldn't rely on such behaviour.
You, the programmer, has to make sure that you don't do illegal memory access. You should not cast the result of malloc. Also, malloc can fail to allocate memory in which case it returns NULL, the null pointer, which you should take care of. You can combine the two statements into one.
int length = 8; // you can also use a macro
char *arr = malloc(length * sizeof *arr);
if(arr) {
// malloc call successful
// do stuff with arr
}

How to allocate memory for an arbitrary-sized array of fixed-length C strings

I am trying to allocate memory for an array of C strings. I can guarantee that the strings fit within MAX_STRING_LENGTH characters, but I don't know at compile time how many strings will be in the array (this is computed dynamically). When I use the code...
char *strings[MAX_STRING_LENGTH] = malloc( sizeof(char *) * numstrings );
...the compiler complains that this is an invalid initializer. When I use the code...
char strings[MAX_STRING_LENGTH][] = malloc( sizeof(char *) * numstrings );
...the compiler complains about an incomplete element type. What am I doing wrong here, and how can I allocate memory for this array?
char (*strings)[MAX_STRING_LENGTH] = malloc(sizeof *strings * num_strings);
will allocate a num_strings x MAX_STRING_LENGTH array of char as a contiguous chunk so that you don't have to do multiple levels of allocation.
strcpy(strings[i], "This is a test");
printf("%s\n", strings[j]);
etc. When you're done you only have to free(strings);.
The main drawbacks with this method are that you may not have enough memory to satisfy the request if num_strings is very large, and that you'll have some internal fragmentation if most of your strings are shorter than MAX_STRING_LENGTH.
With this declaration:
char *strings[MAX_STRING_LENGTH] = malloc(sizeof(char *) * numstrings);
It reads as if you're defining an array of C strings, whose count - not the individual string lengths - is MAX_STRING_LENGTH.
Better to define a **char, like so:
char **strings = malloc(sizeof(char *) * numstrings);
Later in your code, when you're ready to add a string to e.g. slot 5:
strings[5] = malloc(sizeof(char) * MAX_STRING_LENGTH));
or in an init loop such as:
for (i = 0; i < numstrings; i++)
strings[i] = malloc(sizeof(char) * MAX_STRING_LENGTH);
And, if at some point you need room for more strings, use realloc to grow the initial memory allocation.
char **strings;
strings=(char **) malloc(number of strings);
strings[i]=(char *) malloc(MAX_STRING_LENGTH);
If it is truly dynamic, then it may need to be something like this:
char **strings = malloc( sizeof(char*) * numstrings );
for ( int i = 0; i < numstrings; i++ )
strings[i] = malloc( MAX_STRING_LENGTH );
It is also possible to allocate it all in one chunk (makes freeing it easier) and then assign the individual pointers in the array to computed positions in the allocated buffer. That, though, adds some complexity that may not exceed the benefit.

Another dynamic memory allocation bug

I'm trying to allocate memory for a multidimensional array (8 rows, 3 columns).
Here's the code for the allocation (I'm sure the error is clear for you)
char **ptr = (char **) malloc( sizeof(char) * 8);
for (i = 0; i < 3; i++)
ptr[i] = (char *) malloc( sizeof(char) * 3);
The crash happens when I reference this:
ptr[3][0];
Unhandled exception at 0x0135144d in
xxxx.exe:
0xC0000005: Access violation writing
location 0xabababab.
Are there any recommended references/readings for this kind of subject?
Thanks.
The first malloc() is wrong. It should be:
malloc(sizeof(char*) * 8)
A char* is 4 byte (or 8 byte... see P.S) whereas char is 1 byte. When you write ptr[3] the compiler will assume that you want to access to the base address of ptr + 3*sizeof(char*). So you will access to memory that you didn't allocate.
P.S:
To be more precise, char* is 4 byte on 32 bit systems and 8 byte on 64 bit systems.
I don't know offhand any books on memory allocation, but any introductory C tutorial should explain it. As for your bug, your for loop only initializes the first 3 rows, instead of the 8 you allocated. It should be:
for (i = 0; i < 8; i++)
char **ptr = (char **) malloc( sizeof(char *) * 8);
Before, you were allocating space for 8 chars. You want space for 8 pointers to char.
Michael pointed out the other error, writing the first char from a string you never allocated.
It may help if you use constants, like:
const int STRING_COUNT = 8;
const int STRING_LEN = 2;
char **ptr = (char **) malloc( sizeof(char *) * STRING_COUNT);
ptr is an array of 8 pointers, not chars, so the first line should be:
char **ptr = (char **) malloc( sizeof(char*) * 8)
Because there are 8 pointers, the loop should go from 0 to 7:
for (i = 0; i < 8; i++)
You can also consider using a less prone to errors version of the first line:
char **ptr = (char **) malloc( sizeof(*ptr) * 8)
And the last one:
ptr[i] = (char *) malloc( sizeof(*ptr[i]) * 3);
The rule is: always take sizeof of dereferenced lvalue. If lvalue is ptr, then you need sizeof(*ptr). ptr[i] becomes sizeof(*ptr[i]).
There are several errors/inconsistencies in your code, but the first major one is the wrong sizeof in the first allocation. The error that you made could have easily been avoided if you followed some good-practice guidelines:
(1) As much as possible avoid using type names in statements. Type names belong in declarations, not in statements.
(2) Don't cast the result of memory allocation functions.
The first allocation should have looked as follows
char **ptr = malloc( 8 * sizeof *ptr );
Try to remember this as a generic pattern: malloc requestes should normally look as follows
pointer = malloc( count * sizeof *pointer );
Note: no type names are mentioned in the above statement.
Of course, you should also make up your mind about the first size of your 2D array. You attempt to allocate 8, then you only initialize 3. Why?
There are two problems.
First, as others have pointed out, your initial malloc should be
malloc(sizeof(char *) * 8)
Second, you are initializing the first three elements in the 8-element array, but ptr[3][0] refers to the fourth element. Thus the crash.

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