Dynamically allocate struct of char array and int array - c

I am trying to use malloc to allocate memory for a struct containing a char array and an int array. I will be populating these two arrays with information from a file whose length I will not know in advance.
typedef struct bulk_data{
int *l_bulk_pos_arr;
char (*l_bulk_anc_arr)[10001];
}bulk_data;
I am still learning memory allocation, but what I imagine here is that since the size of each char array element is fixed, I shouldn't have to loop through that array to allocate memory. At this point I now know the number of array elements I need (n_rows). I have tried the following (obviously not all at the same time):
struct bulk_data *bulk_counts;
bulk_counts = malloc(sizeof(bulk_data)); // 1st attempt
bulk_counts = (bulk_data *)malloc(sizeof(bulk_data)); // 2nd
bulk_counts = malloc(sizeof(bulk_data) * n_rows); // 3rd
bulk_counts = (bulk_data *)malloc(sizeof(bulk_data) * n_rows); // 4th
No errors at compile time, but it appears that the above listed attempts aren't allocating the space properly:
(gdb) p bulk_counts->l_bulk_anc_arr
$1 = (char (*)[10001]) 0x0
(gdb) p bulk_counts->l_bulk_anc_arr[0]
Cannot access memory at address 0x0
(gdb) p bulk_data->l_bulk_pos_arr
$2 = (int *) 0x0
(gdb) p bulk_data->l_bulk_pos_arr[0]
Cannot access memory at address 0x0
I would like to know how I can allocate memory for this stated case, but also in the case when you don't know the number of chars in each char array element.

l_bulk_anc_arr is a pointer to an array of 10001 chars. It is not an array.
You still have to allocate memory for it.
struct bulk_data *bulk_counts;
bulk_counts = malloc(sizeof(bulk_data));
bulk_counts->l_bulk_pos_arr = malloc( /*some size*/ );
bulk_counts->l_bulk_anc_arr = malloc(10001);
Now, you can use:
(*bulk_counts->l_bulk_anc_arr)[0] = 'a';
(*bulk_counts->l_bulk_anc_arr)[1000] = '\0';
or
bulk_counts->l_bulk_anc_arr[0][0] = 'a';
bulk_counts->l_bulk_anc_arr[0][1000] = '\0';

Related

How to use double pointer as pointer arrays?

Version 1:
struct mydef_s1 {
int argc;
char *argv[3];
};
struct mydef_s1 *p1 = (struct mydef_s1*) malloc (sizeof (struct mydef_s1));
p1->argv[0] = malloc (8);
p1->argv[1] = malloc (16);
p1->argv[2] = malloc (24);
Now, I want to achieve above with the following structure declaration?
Version 2:
struct mydef_s2 {
int argc;
char **argv;
};
If I am right, then following would like allocate just 8 bytes (4 for memory pointer & 4 for integer in my machine)
struct mydef_s2 *p2 = (struct mydef_s2*) malloc (sizeof (struct mydef_s2));
What should I do to do the following?
p2->argv[0]= malloc(4);
p2->argv[1]=malloc(8);
In the case of a pointer to pointer like
struct mydef_s2 {
int argc;
char **argv;
};
you have to first allocate the memory for argv itself, then for argv[i]s.
Something like (code is without error check)
argv = malloc(n * sizeof*argv); //allocate memory to hold 'n' number of 'argv[i]'s
for (i = 0; i < n; i++)
argv[i] = malloc(32); //allocate individual `argv[i]`s
will do the job.
A pointer in C is behaving somewhat like an array. A pointer to pointer, however, is something completely different than a two dimensional array.
If you meant what you typed, i.e. - an array of a non (compiled time) known size of pointers to arrays of non compiled time known sizes of chars, then you will need to do just that. Allocate storage for the array of pointers, place that in your argv, and then initialize each position there with a pointer, possibly dynamically allocated with malloc, of the actual array of chars.
If, on the other hand, you meant a two dimensional array, you have two ways to proceed. One is to do the above, possibly saving a step by allocating the inner nesting in one malloc at one go. This is somewhat wasteful in memory.
The other option is to simulate what the compiler does for two dimensional arrays. Allocate n*m chars as a single dimension array, and jump into it by with the formula i = r*m + c, where r is the row index, m is the row size, and c is the column index.
While somewhat verbose, this is what C does when you define a two dimensional array. It is also quicker to allocate, initialize and use than the alternative.

pointer to pointer to structure with malloc and strdup

My main intention is to pass a pointer to a structure, to a function, which will allocate memory and fill all its values. After returning back i will print it on screen.
Structure looks like this.
struct isolock{
char *name;
unsigned int state;};
typedef struct isolock lock;
Please note i can not change declaration of this structure. My main function is very simple like this.
int main(){
int i = 0;
isolock *lock = NULL;
fillArray(&lock);
//print struct contents
for(i=0;(lock+i)->name;i++){
printf("name = %s status = %u \n", (lock+i)->name,(lock+i)->state);
}
}
fillArray function is suppose to allocate n + 1 memory blocks for my structure where n is the actual number of locks present. whereas last (n+1)th block will be filled with zero. So that while printing from main, i can just check for this condition, without need of worrying about length of structures which i have allocated.
My problem is in fillArray function.
static const char *array[] = {"SWMGMT_LOCK","OTHER_LOCK"};
void fillArray(isolock **dlock){
int i = 0;
if (*dlock == NULL){
*dlock = (isolock *)malloc((sizeof (*dlock)) * 3); //allocate space for holding 3 struct values
for(i=0;i<2;i++){
(*(dlock) + i)->name = strdup(array[i]);
(*(dlock) + i)->state = (unsigned int)(i+1);
}
(*(dlock) + i)->name = 0; //LINE100
(*(dlock) + i)->state = 0;
}
}
o/p:
name = status = 1
name = OTHER_FP_LOCK status = 2
Actually this LINE100 causes problem. It actually replaces already filled structure entry i.e., this line makes dlock[0]->name to be filled with 0. whereas dlock[1] remains unchanged.
My gdb log shows something like this.
All these are logs are taken after allocation and filling values.
(gdb) p (*(dlock)+0)
$10 = (isolock *) 0x804b008
(gdb) p (*(dlock)+1)
$11 = (isolock *) 0x804b010
(gdb) p (*(dlock)+2) <== Note here 1
$12 = (isolock *) 0x804b018
(gdb) p *(*(dlock)+0)
$13 = {name = 0x804b018 "SWMGMT_LOCK", state = 1} <== Note here 2
(gdb) p *(*(dlock)+1)
$14 = {name = 0x804b028 "OTHER_FP_LOCK", state = 2}
(gdb) n
33 (*(dlock) + i)->state = 0;
(gdb)
35 }
(gdb) p *(*(dlock)+2)
$15 = {name = 0x0, state = 0}
(gdb) p (*(dlock)+2)
$16 = (isolock *) 0x804b018
From note 1 and note 2 its very clear that, strdup has returned already allocated memory location by malloc i.e., first call to strdup has returned the address of dlock[2]. how could this happen. because of this, (*dlock+2)->name = 0 has caused dlock[0]->name to be filled with 0.
To easily explain this problem,
Malloc has returned me three addresses. for easy understanding lets say, {1000,1008,1010}
Two times i ve called strdup which has returned {1010,1018}
this 1010 and 1018 are stored in char *name of lock[0] and lock[1] respectively.
Can someone tell me, am i doing something wrong in this code or is this problem of strdup ( allocating a already allocated block of memory)
NOTE: When i have changed char *name to char name[20] and instead of strdup, i used strcpy and it worked perfectly.
A possible cause of the error is your allocation:
*dlock = (isolock *)malloc((sizeof (*dlock)) * 3);
Here dlock is a pointer to a pointer, so sizeof(*dlock) is the size of a pointer which is not the same as sizeof(struct isolock) (or sizeof(**dlock)).

How to access allocated memory in C?

After using malloc() to initialize 5000 bytes of memory, how would I reference the bytes in this memory space? For example, if I need to point to a starting location of data within the memory, how would I go about that?
EDIT: Does it matter what I use to point to it? I mean I am seeing people use bytes/int/char? Is it relevant?
Error I get:
You can use the subscript array[n] operator to access the index you are interested in reading/writing, like so:
uint8_t* const bytes = (uint8_t*)malloc(5000);
bytes[0] = UINT8_MAX; // << write UINT8_MAX to the first element
uint8_t valueAtIndexZero = bytes[0]; // << read the first element (will be UINT8_MAX)
...
free(bytes), bytes = 0;
char * buffer = malloc(5000);
buffer[idx] = whatever;
char * p = buffer + idx;
*p = whatever;
Malloc doesn't initialize the bits allocated by it. Use calloc() rather.
int *p = malloc (5000); // p points to the start of the dynamically allocated area.
As has been mentioned by others, you could do something like this:
int nbytes = 23; // number of bytes of space to allocate
byte *stuff = malloc(nbytes * sizeof stuff[0]);
stuff[0] = 0; // set the first byte to 0
byte x = stuff[0]; // get the first byte
int n = 3;
stuff[n] = 0; // set the nth byte to 0
x = stuff[n]; // nth byte, or in the case of some other type, nth whatever - just make sure it's a safe value, from 0 (inclusive) to the number (nbytes here) of things you allocated (exclusive)
However, a couple of things to note:
malloc will not initialise the memory, but calloc will (as mentioned by Prasoon Saurav)
You should always check to see if the memory allocation failed (see below for an example)
int nbytes = 23; // or however many you want
byte *stuff = malloc(nbytes * sizeof stuff[0]);
if (NULL == stuff) // memory allocation failed!
{
//handle it here, e.g. by exiting the program and displaying an appropriate error message
}
stuff[0] = 0; // set the first byte to 0
byte x = stuff[0]; // get the first byte
int n = 3;
stuff[n] = 0; // set the nth byte to 0
x = stuff[n]; // nth byte, or in the case of some other type, nth whatever
malloc() returns a pointer to the allocated memory:
typedef unsigned char byte;
byte * mem = malloc( 5000 );
byte val = mem[1000]; /* gets the 1000th byte */
After using malloc() to initialize 5000 bytes of memory, how would I
reference the bytes in this memory space? For example, if I need to
point to a starting location of data within the memory, how would I go
about that?
Does it matter what I use to point to it? I mean I am seeing people
use bytes/int/char? Is it relevant?
as you have seen malloc allocates a block of memory counted in bytes, you can assign a pointer to that block and depending on the pointer type the compiler knows how to reference individual elements:
unsigned char *memblob = malloc( 1024 );
short* pshort = (short*)memblob;
now if you reference the second short value i.e. *(pshort + 1) or pshort[1] the compiler knows that it needs to add 2 bytes (sizeof(short)) in order get the next element.
float* pfloat = (float*)memblob;
now if you reference the second float value i.e. *(pfloat + 1) or pfloat[1] the compiler knows that it needs to add 4 bytes (sizeof(float)) in order get the next element.
same with own defined data types:
typedef struct s
{
short a;
long b;
} mystruct_t;
mystruct_t* pstruct = (mystruct_t*)memblob;
pstruct + 1 accesses the struct at offset sizeof(mystruct_t)
so it is really up to you how you want to use the allocated memory

Dynamic memory allocation code explanation

Being a beginner C/C++ programmer, I am having to spend several hours, trying to decipher the code below: Could someone walk me (step me through the code below for dynamic memory allocation) line by line.
char **alloc_2d_char(const int rows, const int cols)
{
char *data = (char *)malloc(rows*cols*sizeof(char));
char **array= (char **)malloc(rows*sizeof(char*));
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
return array;
}
Pointer to Pointers is explained separately than from Pointers to Arrays. I have been able to get parts of the information from various sources, but none that stitches the lines cohesively.
The code is using a single contiguous block of memory to hold a 2-D array.
char *data = (char *)malloc(rows*cols*sizeof(char));
Ok -- this line is allocating space for the entire 2-D array. The 2-D array is rows rows by cols columns. So the total number of elements is rows * cols. Then you have to multiply that by the amount of space each element takes up, which is sizeof(char) since this is a 2-D array of char. Thus the total amount of memory to be allocated is rows * cols * sizeof(char) which is indeed the argument to malloc.
The malloc call returns a pointer to the allocated memory. Since this memory will be used to hold char, you cast the return value to char *.
char **array= (char **)malloc(rows*sizeof(char*));
array is being declared as type "pointer to pointer to char" because that's what it's going to do. It'll point to memory that will hold pointers to char. It will be one pointer for each row. So you have to allocate rows * sizeof(char *) memory: the number of pointers times the size of a pointer of the right type. And since this was allocated to point to pointers to char, we cast the return value to char **.
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
This is the magic :). This sets each pointer in array to point to within the block of actual data allocated earlier. Consider a concrete example where rows is 2 and cols is 3. Then you have the block of 6 characters in memory:
[0][1][2][3][4][5]
And data[n] (for n from 0 to 5) is the n-th element and &data[n] is the *address of the n-th element.
So what that loop does in this case is do:
array[0] = &data[0];
array[1] = &data[3];
So array[0] points to the sub-block starting at [0] and array[1] points to the sub-block starting at [3]. Then when you add the second subscript you're indexing from the start of that pointer. So array[0][2] means "get the pointer stored in array[0]. Find what it points to, then move ahead 2 elements from there.:
array[0] points to [0][1][2] (well, actually points to [0]). Then you move two elements ahead and get [2].
Or if you start with array[1][1], array[1] points to [3][4][5] (and actually points at [3]. Move one element ahead and get [4].
The first malloc is getting memory for the 2D character array. The second malloc is getting memory for rows index.
The for loop is setting the pointer to each row.
Finally the row index is returned.
You can think of the 2-D array that it is creating as an array of single-dimensional arrays. Each row entry points to an array of char that represents the column data for that row.
The following is the original code with comments added to attempt to describe each step:
char **alloc_2d_char(const int rows, const int cols)
{
// This allocates the chunk of memory that stores that actual data.
// It is a one single-dimensional array that has rows*cols characters.
char *data = (char *)malloc(rows*cols*sizeof(char));
// This allocates an array of pointers that will then be assigned to the
// individual rows (carved out of the previous allocation).
char **array= (char **)malloc(rows*sizeof(char*));
// This assigns each row to the appropriate position in the data array.
// The &(data[cols*i]) bit of it is the address of a portion in the
// memory pointed to by data. The cols*i is the offset to the portion that
// represents row i.
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
// After doing this, then you can assign a value such as:
// array[r][c] = 'x';
// That statement would store 'x' into data[r*c + c]
return array;
}
Is not hard to decipher...
char *data = (char *)malloc(rows*cols*sizeof(char));
simple memory allocation
char **array= (char **)malloc(rows*sizeof(char*));
memory allocation of #row char pointers
array[i] = &(data[cols*i]);
every array[i] is a pointer, a pointer to data[cols*i]
Each * in a declaration refers to one level of pointer indirection. so int ** means a pointer to a pointer to an int. So your function:
char **alloc_2d_char(const int rows, const int cols)
{
returns a pointer to a pointer to a char.
char *data = (char *)malloc(rows*cols*sizeof(char));
This declares a pointer to a char. The pointer is called data. The initialization calls malloc, which allocates a number of bytes equal to the value of the argument. This means there are rows*cols*sizeof(char) bytes, which will be equal to rows*cols, since a char is 1 byte. The malloc function returns the pointer to the new memory, which means that data now points to a chunk of memory that's rows*cols big. The (char *) before the call to malloc just casts the new memory to the same type as the pointer data.
char **array= (char **)malloc(rows*sizeof(char*));
array is a pointer to a pointer to a char. It is also being assigned using malloc. The amount of memory being allocated this time is rows*sizeof(char), which is equal to rows. This means that array is a pointer to a pointer to a chunk of memory big enough to hold 1 row.
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
The rest of your code initializes each element of array to hold the address of the corresponding row of the big chunk of memory. Your data pointer will point to a chunk of memory that looks like this:
col: 0 1 2 3 ... cols-1
row: 0 *
1 *
2 *
3 *
.
.
.
rows-1 *
And your array pointer will point to a chunk of memory with a list of pointers, each of which points to one of the asterisks in the memory chunk above.
return array;
}
This just returns your array pointer to a pointer, which matches the return type of the alloc_2d_char function: char **. This means that the caller of the function will essentially obtain an array of pointers, and each of these pointers points to one of the rows of the 2D array.

C: delete array

I'm new in c. I want to create array, and after it delete it, and then put another array into it. How can I do it?
If you are looking for a dynamic array in C they are fairly simple.
1) Declare a pointer to track the memory,
2) Allocate the memory,
3) Use the memory,
4) Free the memory.
int *ary; //declare the array pointer
int size = 20; //lets make it a size of 20 (20 slots)
//allocate the memory for the array
ary = (int*)calloc(size, sizeof(int));
//use the array
ary[0] = 5;
ary[1] = 10;
//...etc..
ary[19] = 500;
//free the memory associated with the dynamic array
free(ary);
//and you can re allocate some more memory and do it again
//maybe this time double the size?
ary = (int*)calloc(size * 2, sizeof(int));
Information on calloc() can be found here, the same thing can be accomplished with malloc() by instead using malloc(size * sizeof(int));
It sounds like you're asking whether you can re-use a pointer variable to point to different heap-allocated regions at different times. Yes you can:
void *p; /* only using void* for illustration */
p = malloc(...); /* allocate first array */
... /* use the array here */
free(p); /* free the first array */
p = malloc(...); /* allocate the second array */
... /* use the second array here */
free(p); /* free the second array */

Resources