Array of pointers initialization - c

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.

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;
}

Dynamically allocating memory for 2d char array

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;
}

Memory allocation for a char ** pointer in 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.

receive a segmentation error when printing out words of array

The following is a piece of code where the user enters unknown amounts of words until 'E' is entered, whereupon the program should stop and print out all of the entered words. However, when run this program produces a segmentation error. Did I access some memory I shouldn't have?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 10
#define NUM_OF_WORDS 10
int main(void)
{
int num_words = 10;
char *word= malloc(CAPACITY*sizeof(char));
char **w=(char **) malloc(num_words*sizeof(char));
int i;
for(i = 0 ; scanf("%s", word)==1; ++i)
{
if(*word == 'E')
break;
if( i == num_words-1)
w = (char **)realloc(w, (num_words *=2) * sizeof(char));
w[i] =(char *) malloc(strlen(word)+1 * sizeof(char));
strcpy(w[i], word);
}
int x = 0;
for(x = 0 ; x<num_words ; x++)
printf("%s", w[x]);
return 0;
}
Your initial allocation code reads:
char *word = malloc(CAPACITY*sizeof(char));
char **w = (char **) malloc(num_words*sizeof(char));
Both these allocate 10 bytes of memory. Your second one should read:
char **w = (char **) malloc(num_words*sizeof(char *));
or:
char **w = malloc(num_words*sizeof(*w));
These both allocate enough memory for 10 pointers (which might be eight times as much memory as your original code). The second is arguably better style; the first is indubitably the classic style. In C, the cast on malloc() is not necessary; in C++, it is.
This may not be the whole problem; it is almost certainly a contributory factor.
Also, you aren't checking your memory allocations; that is not advisable. You should always check them.
This code:
if (i == num_words-1)
w = (char **)realloc(w, (num_words *=2) * sizeof(char));
is playing with fire on two accounts (plus a repeat of the previously diagnosed problem):
The assignment within the argument list is...not generally reckoned to be a good idea. I wouldn't write code with that in place, and I'd send back code I was asked to review that contained it. It isn't technically wrong; it will work. But it does not make life easier for the maintenance programmers who come after.
You should never reallocate a pointer such as w and assign the new space to the same pointer. If the memory allocation fails, you'll get back a null pointer, so you've lost the only pointer to the previous data, which is still allocated. That's a memory leak. Also, if the memory allocation fails, you have to undo the assignment within the argument list because the allocated space is still at the original size. I think you'd be better off using:
if (i == num_words - 1)
{
size_t new_size = (num_words * 2);
char **new_data = realloc(w, new_size * sizeof(*new_data));
if (new_data == 0)
...handle error; w is still valid, and num_words is still correct too...
num_words = new_size;
w = new_data;
}
Your variable num_words holds the current maximum size of the w array, but that isn't the same as the number of words actually in the array.
When you loop through the w array you are looping through too many items - some elements of the w do not have a valid string in them - trying to print them will cause a segfault.

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.

Resources