C: pointer to array of pointers to structures (allocation/deallocation issues) - c

I've been getting back into C for something, but I'm having trouble remembering much of how this memory management works. I'd like to have a pointer to an array of pointers to structures.
Say I have:
struct Test {
int data;
};
Then the array:
struct Test **array1;
Is this correct? My issue is working with this thing. So each pointer in the array points to something that is allocated separately. But I think I need to do this first:
array1 = malloc(MAX * sizeof(struct Test *));
I am having trouble understanding the above. Do I need to do this, and why do I need to do this? In particular, what does it mean to allocate memory for pointers if I am going to be allocating memory for each thing that the pointer points to?
Say now I have pointer to an array of pointers to structures. I now want it to point to the same array that I've created earlier.
struct Test **array2;
Do I need to allocate room for pointers like I did above, or can I just do:
array2 = array1

Allocated Array
With an allocated array it's straightforward enough to follow.
Declare your array of pointers. Each element in this array points to a struct Test:
struct Test *array[50];
Then allocate and assign the pointers to the structures however you want. Using a loop would be simple:
array[n] = malloc(sizeof(struct Test));
Then declare a pointer to this array:
// an explicit pointer to an array
struct Test *(*p)[] = &array; // of pointers to structs
This allows you to use (*p)[n]->data; to reference the nth member.
Don't worry if this stuff is confusing. It's probably the most difficult aspect of C.
Dynamic Linear Array
If you just want to allocate a block of structs (effectively an array of structs, not pointers to structs), and have a pointer to the block, you can do it more easily:
struct Test *p = malloc(100 * sizeof(struct Test)); // allocates 100 linear
// structs
You can then point to this pointer:
struct Test **pp = &p
You don't have an array of pointers to structs any more, but it simplifies the whole thing considerably.
Dynamic Array of Dynamically Allocated Structs
The most flexible, but not often needed. It's very similar to the first example, but requires an extra allocation. I've written a complete program to demonstrate this that should compile fine.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Test {
int data;
};
int main(int argc, char **argv)
{
srand(time(NULL));
// allocate 100 pointers, effectively an array
struct Test **t_array = malloc(100 * sizeof(struct Test *));
// allocate 100 structs and have the array point to them
for (int i = 0; i < 100; i++) {
t_array[i] = malloc(sizeof(struct Test));
}
// lets fill each Test.data with a random number!
for (int i = 0; i < 100; i++) {
t_array[i]->data = rand() % 100;
}
// now define a pointer to the array
struct Test ***p = &t_array;
printf("p points to an array of pointers.\n"
"The third element of the array points to a structure,\n"
"and the data member of that structure is: %d\n", (*p)[2]->data);
return 0;
}
Output:
> p points to an array of pointers.
> The third element of the array points to a structure,
> and the data member of that structure is: 49
Or the whole set:
for (int i = 0; i < 100; i++) {
if (i % 10 == 0)
printf("\n");
printf("%3d ", (*p)[i]->data);
}
35 66 40 24 32 27 39 64 65 26
32 30 72 84 85 95 14 25 11 40
30 16 47 21 80 57 25 34 47 19
56 82 38 96 6 22 76 97 87 93
75 19 24 47 55 9 43 69 86 6
61 17 23 8 38 55 65 16 90 12
87 46 46 25 42 4 48 70 53 35
64 29 6 40 76 13 1 71 82 88
78 44 57 53 4 47 8 70 63 98
34 51 44 33 28 39 37 76 9 91
Dynamic Pointer Array of Single-Dynamic Allocated Structs
This last example is rather specific. It is a dynamic array of pointers as we've seen in previous examples, but unlike those, the elements are all allocated in a single allocation. This has its uses, most notable for sorting data in different configurations while leaving the original allocation undisturbed.
We start by allocating a single block of elements as we do in the most basic single-block allocation:
struct Test *arr = malloc(N*sizeof(*arr));
Now we allocate a separate block of pointers:
struct Test **ptrs = malloc(N*sizeof(*ptrs));
We then populate each slot in our pointer list with the address of one of our original array. Since pointer arithmetic allows us to move from element to element address, this is straight-forward:
for (int i=0;i<N;++i)
ptrs[i] = arr+i;
At this point the following both refer to the same element field
arr[1].data = 1;
ptrs[1]->data = 1;
And after review the above, I hope it is clear why.
When we're done with the pointer array and the original block array they are freed as:
free(ptrs);
free(arr);
Note: we do NOT free each item in the ptrs[] array individually. That is not how they were allocated. They were allocated as a single block (pointed to by arr), and that is how they should be freed.
So why would someone want to do this? Several reasons.
First, it radically reduces the number of memory allocation calls. Rather then N+1 (one for the pointer array, N for individual structures) you now have only two: one for the array block, and one for the pointer array. Memory allocations are one of the most expensive operations a program can request, and where possible, it is desirable to minimize them (note: file IO is another, fyi).
Another reason: Multiple representations of the same base array of data. Suppose you wanted to sort the data both ascending and descending, and have both sorted representations available at the same time. You could duplicate the data array, but that would require a lot of copying and eat significant memory usage. Instead, just allocate an extra pointer array and fill it with addresses from the base array, then sort that pointer array. This has especially significant benefits when the data being sorted is large (perhaps kilobytes, or even larger, per item) The original items remain in their original locations in the base array, but now you have a very efficient mechanism in which you can sort them without having to actually move them. You sort the array of pointers to items; the items don't get moved at all.
I realize this is an awful lot to take in, but pointer usage is critical to understanding the many powerful things you can do with the C language, so hit the books and keep refreshing your memory. It will come back.

It may be better to declare an actual array, as others have suggested, but your question seems to be more about memory management so I'll discuss that.
struct Test **array1;
This is a pointer to the address of a struct Test. (Not a pointer to the struct itself; it's a pointer to a memory location that holds the address of the struct.) The declaration allocates memory for the pointer, but not for the items it points to. Since an array can be accessed via pointers, you can work with *array1 as a pointer to an array whose elements are of type struct Test. But there is not yet an actual array for it to point to.
array1 = malloc(MAX * sizeof(struct Test *));
This allocates memory to hold MAX pointers to items of type struct Test. Again, it does not allocate memory for the structs themselves; only for a list of pointers. But now you can treat array as a pointer to an allocated array of pointers.
In order to use array1, you need to create the actual structs. You can do this by simply declaring each struct with
struct Test testStruct0; // Declare a struct.
struct Test testStruct1;
array1[0] = &testStruct0; // Point to the struct.
array1[1] = &testStruct1;
You can also allocate the structs on the heap:
for (int i=0; i<MAX; ++i) {
array1[i] = malloc(sizeof(struct Test));
}
Once you've allocated memory, you can create a new variable that points to the same list of structs:
struct Test **array2 = array1;
You don't need to allocate any additional memory, because array2 points to the same memory you've allocated to array1.
Sometimes you want to have a pointer to a list of pointers, but unless you're doing something fancy, you may be able to use
struct Test *array1 = malloc(MAX * sizeof(struct Test)); // Pointer to MAX structs
This declares the pointer array1, allocated enough memory for MAX structures, and points array1 to that memory. Now you can access the structs like this:
struct Test testStruct0 = array1[0]; // Copies the 0th struct.
struct Test testStruct0a= *array1; // Copies the 0th struct, as above.
struct Test *ptrStruct0 = array1; // Points to the 0th struct.
struct Test testStruct1 = array1[1]; // Copies the 1st struct.
struct Test testStruct1a= *(array1 + 1); // Copies the 1st struct, as above.
struct Test *ptrStruct1 = array1 + 1; // Points to the 1st struct.
struct Test *ptrStruct1 = &array1[1]; // Points to the 1st struct, as above.
So what's the difference? A few things. Clearly, the first method requires you to allocate memory for the pointers, and then allocate additional space for the structs themselves; the second lets you get away with one malloc() call. What does the extra work buy you?
Since the first method gives you an actual array of pointers to Test structs, each pointer can point to any Test struct, anywhere in memory; they needn't be contiguous. Moreover, you can allocate and free the memory for each actual Test struct as necessary, and you can reassign the pointers. So, for example, you can swap two structures by simply exchanging their pointers:
struct Test *tmp = array1[2]; // Save the pointer to one struct.
array1[2] = array1[5]; // Aim the pointer at a different struct.
array1[5] = tmp; // Aim the other pointer at the original struct.
On the other hand, the second method allocates a single contiguous block of memory for all of the Test structs and partitions it into MAX items. And each element in the array resides at a fixed position; the only way to swap two structures is to copy them.
Pointers are one of the most useful constructs in C, but they can also be among the most difficult to understand. If you plan to continue using C, it'll probably be a worthwhile investment to spend some time playing with pointers, arrays, and a debugger until you're comfortable with them.
Good luck!

I suggest that you build this out a layer at a time using typdefs to create layers of types. By doing so, the different types needed will be much clearer.
For instance:
typedef struct Test {
int data;
} TestType;
typedef TestType * PTestType;
This will create two new types, one for the struct and one for a pointer to the struct.
So next if you want an array of the structs then you would use:
TestType array[20]; // creates an array of 20 of the structs
If you want an array of pointers to the structs then you would use:
PTestType array2[20]; // creates an array of 20 of pointers to the struct
Then if you want to allocate structs into the array you would do something like:
PTestType array2[20]; // creates an array of 20 of pointers to the struct
// allocate memory for the structs and put their addresses into the array of pointers.
for (int i = 0; i < 20; i++) {
array2 [i] = malloc (sizeof(TestType));
}
C does not allow you to assign one array to another. You must instead use a loop to assign each element of one array to an element of the other.
EDIT: Another Interesting Approach
Another approach would be a more object oriented approach in which you encapsulate a few things. For instance using the same layers of types we create two types:
typedef struct _TestData {
struct {
int myData; // one or more data elements for each element of the pBlob array
} *pBlob;
int nStructs; // count of number of elements in the pBlob array
} TestData;
typedef TestData *PTestData;
Next we have a helper function which we use to create the object, named appropriately enough CreateTestData (int nArrayCount).
PTestData CreateTestData (int nCount)
{
PTestData ret;
// allocate the memory for the object. we allocate in a single piece of memory
// the management area as well as the array itself. We get the sizeof () the
// struct that is referenced through the pBlob member of TestData and multiply
// the size of the struct by the number of array elements we want to have.
ret = malloc (sizeof(TestData) + sizeof(*(ret->pBlob)) * nCount);
if (ret) { // make sure the malloc () worked.
// the actual array will begin after the end of the TestData struct
ret->pBlob = (void *)(ret + 1); // set the beginning of the array
ret->nStructs = nCount; // set the number of array elements
}
return ret;
}
Now we can use our new object as in the source code segment below. It should check that the pointer returned from CreateTestData() is valid however this is really just to show what could be done.
PTestData go = CreateTestData (20);
{
int i = 0;
for (i = 0; i < go->nStructs; i++) {
go->pBlob[i].myData = i;
}
}
In a truly dynamic environment you may also want to have a ReallocTestData(PTestData p) function that would reallocate a TestData object in order to modify the size of the array contained in the object.
With this approach, when you are done with a particular TestData object, you can just free the object as in free (go) and the object and its array are both freed at the same time.
Edit: Extending Further
With this encapsulated type we can now do a few other interesting things. For instance, we can have a copy function, PTestType CreateCopyTestData (PTestType pSrc) which would create a new instance and then copy the argument to a new object. In the following example, we reuse the function PTestType CreateTestData (int nCount) that will create an instance of our type, using the size of the object we are copying. After doing the create of the new object, we make a copy of the data from the source object. The final step is to fix up the pointer which in the source object points to its data area so that pointer in the new object now points to the data area of itself rather than the data area of the old object.
PTestType CreateCopyTestData (PTestType pSrc)
{
PTestType pReturn = 0;
if (pSrc) {
pReturn = CreateTestData (pSrc->nStructs);
if (pReturn) {
memcpy (pReturn, pSrc, sizeof(pTestType) + pSrc->nStructs * sizeof(*(pSrc->pBlob)));
pReturn->pBlob = (void *)(pReturn + 1); // set the beginning of the array
}
}
return pReturn;
}

Structs are not very different from other objects. Let's start with characters:
char *p;
p = malloc (CNT * sizeof *p);
*p is a character, so sizeof *p is sizeof (char) == 1; we allocated CNT characters. Next:
char **pp;
pp = malloc (CNT * sizeof *pp);
*p is a pointer to character, so sizeof *pp is sizeof (char*). We allocated CNT pointers. Next:
struct something *p;
p = malloc (CNT * sizeof *p);
*p is a struct something, so sizeof *p is sizeof (struct something). We allocated CNT struct somethings. Next:
struct something **pp;
pp = malloc (CNT * sizeof *pp);
*pp is a pointer to struct, so sizeof *pp is sizeof (struct something*). We allocated CNT pointers.

Related

2D Array of structs in C?? (maybe) [duplicate]

This question already has answers here:
Large VLA overflow
(1 answer)
Getting a stack overflow exception when declaring a large array
(8 answers)
Closed 3 years ago.
I am trying to create a 2d array which each element points to a struct to store values from a CSV file. I am not sure if I am creating the struct or defining the 2d array right though.
Below is my struct and how I allocate the memory. There will always be 35 columns but the rows could grow quite large. When I run this with int test =29000 (or 29000 rows), it works and stores all values in a 2d array I can access by [row][col]. When I assign test with anything greater than 29000 it seg faults without even going into the allocation of the memeory it just segfaults at struct node* arrayofnodes[test][35];
I am very confused as to why it works with 29000 but not with 30000. Also, if anyone has any suggestions on how to malloc the array on one line instead of having to go into 2 for loops, I would be very happy to learn. Also I was wondering If I should use a typedef struct here or not.
Thanks
struct node {
char* value;
};
int test=30000;
struct node* arrayofnodes[test][35];
for (int p=0; p < test; p++){
for (int j=0; j < 35; j++){
arrayofnodes[p][j] = malloc(sizeof(arrayofnodes));
}
}//this works and i can access a certain element by arrayofnodes[row][col].value;
The problem is likely that you're allocating to much on the stack. arrayofnodes will be an array of 30,000*35=1,050,000 pointers, each of which is probably 8 bytes. So you're trying to allocate an array of 8MB on the stack, and 8MB is the default limit for stack size.
This code segfaulted for me:
#include <stdio.h>
int main() {
struct node {
char* value;
};
int test=30000;
struct node* arrayofnodes[test][35];
printf("%d\n", sizeof(arrayofnodes));
}
Also, sizeof(arrayofnodes) is wrong. If the code snippet above wouldn't have segfaulted, it would have printed 8400000. Instead, sizeof struct node or sizeof arrayofnodes[0][0] would give the right result.
A solution could be something like this:
struct node ** array[35];
for(int i=0; i<35; i++) {
array[i] = malloc(test * sizeof array[0]);
for(int j=0; j<test; j++) array[i][j] = malloc(sizeof (struct node));
}
You're allocating a huge amount of memory here: printf("%lu\n", sizeof(arrayofnodes)); reports that arrayofnodes has a size of 30000 * 35 * 8 = 8400000 bytes, making for a total memory allocation of 30000 * 35 * 8400000 = 8820000000000 bytes in your loop.
You might have meant *arrayofnodes[p][j]--allocate space for a pointer to a struct at row p and column j. Note that this doesn't include space for the memory block pointed to by the char *, which will also need to be malloced.
Also, remember that while the heap has plenty of space, the stack doesn't, and 8 * 35 * 30000 is likely more than a stack frame can handle.
Consider avoiding a struct if there's only one field. Using a plain old char * would avoid an extra layer of indirection.
If you'd like to maximize space efficiency at the expense of speed, you might try reading your text file in once to build an array of string sizes for each cell, then malloc everything accordingly for a second pass. You could use a char ***csv_data array containing cells allocated to size csv_cell_size[row][col] or similar.
Flattening your array by a dimension and using an offset to find a particular row/column is another option. Long story short, there are more than a few ways to manage this, with a lot depending on your data and how you plan to use it.
Also, don't forget to free() all your memory when you're done with it.
Your array declaration is being allocated on the stack, the default stack limit is 8MB. When test is 29000 the stack allocation is within the limit (29000 * 35 * 8 = 7.7MB), when you change test to 30000 you are exceeding the stack limit (30000 * 35 * 8 = 8.01MB) which results int the seg fault.
You can get past this by allocating the array on the heap using malloc, just remember to free what you allocate.
#include <stdio.h>
#include <malloc.h>
struct node {
char *value;
};
int rows = 30000;
int cols = 35;
struct node **arrayofnodes;
int main() {
arrayofnodes = (struct node **)malloc(rows * sizeof(struct node*));
for (int row = 0; row < rows; row++) {
arrayofnodes[row] = (struct node *)malloc(cols * sizeof(struct node*));
}
// Use arrayofnodes
// Free allocations after use...
}

Dynamically expanding array of structs C [duplicate]

This question already has answers here:
Dynamic array in C — Is my understanding of malloc and realloc correct?
(3 answers)
Closed 5 years ago.
So for my school project, a large CSV file will be entered through stdin and we will have to sort it based on column and print it out as a sorted csv file.
The step I am on right now is figuring out how to keep reallocing a struct of arrays so that it will grow if there is not big enough to hold the data coming in from stdin. We don't know the exact amount of rows that will be inputted in the CSV file. Right now we just used a static amount to test and see if the values are assigned to the structs.
I am still a beginner at C so I do not clearly know how I would iterate through a pointer like I would iterate through an array. Since we are using a static amount of structs in the array, we can just iterate using array[i] like in Java but how would you iterate through something like *array?
I do not know where to start for creating this dynamic array. I tried
struct array* testArray = (array*)malloc(sizeof(testArray));
but I have no idea how to iterate through it like I did with the static array by using array[i].
Any help would be greatly appreciated, sorry for the wall of text...
You can navigate through a malloced space the same way as with an array (using indicies), but it seems that your main issue lies in your use of malloc. Malloc's argument is the size in number of bytes that you want to allocate. So if you want to have an array of structs, you would first need to find out how many bytes one struct contains using sizeof(struct array), and then determine how large of an array you want, let's say N. So that line of code should look more like struct array* testArray = malloc(N * sizeof(struct array));. The return value of malloc will be a void pointer containing the memory address of the first byte of allocated space. Upon assigning this value to testArray, it will be type-casted to the assigned variable type (struct array *). Now you can use pointer arithmetic to access a specific index i with *(testArray + i), or simply testArray[i]. If you find that N was not a sufficient size, you can use realloc to increase the array size to 2N, or whatever size deemed necessary.
struct array* testArray = (array*)malloc(sizeof(testArray));
is a little wrong as you only allocate 1 element of testArray.
It is more like:
struct A
{
int a;
int b;
....
};
struct A* arr = malloc( N * sizeof(struct A) );
^^^
N element of struct A
int j;
for (j=0; j<N; ++j) // Iterate it like any other array
{
arr[j].a = 5;
arr[j].b = 42;
....
}
Use realloc when you need the array to grow.
When reading from a file/stdin it could look like (based on comment from David C. Rankin):
int n=0; // Count of the number of structs read from the file
struct A* arr = malloc( N * sizeof(struct A) );
while (read line from file)
{
arr[n].a = val1;
arr[n].b = val2;
++n; // Increment count
if (n == N) // Check if current array is full, i.e. realloc needed
{
// realloc array to 2 * N; N = N * 2
}
}

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.

How to send 2D array to a function?

I've created a 2D array using this:
struct Cars (*ParkingLot)[FloorCount] = malloc(sizeof(struct Cars[FloorCount][10]));
I don't know if it matters but the FloorCount is set to 1 for now, and struct Cars is defined this way:
struct Cars
{
int ID;
char color[20];
char type[20];
};
Anyway, I'm trying to use this array in a function, and I can't access the values inside the array.
For example, the next thing:
void CarIn (struct Cars *Lot[])
{
printf("%d", Lot[0][0].ID);
}
ParkingLot[0][0].ID=15;
CarIn(ParkingLot);
That's not what I wanna do, but it's the most basic function I can think of using the array, it will help me with the rest.
Edit:
Well, I've managed to print using the function, all I needed is to add & before the Lot[0][0].ID...
The other problem I have now is that this function doesn't seem to work at all, it always crash:
void CarIn (struct Cars *Lot[],struct Cars New)
{
Lot[0][0]=New;
return;
}
First, your sizing is wrong in your allocation declaration for ParkingLot. I assume you want 10 cars per floor and an arbitrary number of floors, and if that is the case, then this should be done as:
struct Cars (*ParkingLot)[10] = malloc(FloorCount * sizeof *ParkingLot);
ParkingLot is a pointer to an array of 10 Cars (not 10 pointers to Cars; rather 10 Cars in sequence). sizeof *ParkingLot will calculate the memory requirement for holding that many sequential Cars structures, and finally, multiplying by FloorCount will give you that many floors, of that many cars. For sanity sake you could (and probably should) use the array allocator in the standard library, calloc, though it isn't strictly needed. It would look something like this:
struct Cars (*ParkingLot)[10] = calloc(FloorCount, sizeof *ParkingLot);
Some find it clearer, and relish in the fact it zero-initializes the allocated memory.
On to your question, to pass a true array of arrays (as opposed to an array of pointers) your function parameter declaration is incorrect.
This:
void CarIn (struct Cars *Lot[])
declares an arbitrary-length array of struct Cars *, and indeed the above is equivalent to this:
void CarIn (struct Cars **Lot)
You want neither of those if your intent is to pass a true array of arrays (which is what your allocation is indeed acquiring). Instead, you want something like this:
void CarIn (struct Cars Lot[][10])
or equivalently, this:
void CarIn (struct Cars (*Lot)[10])
To pass a true array of arrays to a function, all dimensions but the most-superior must be provided in the declaration. The above declare an arbitrary length array of element-count-10 arrays of Cars.
Note: This can be done with variable-length syntax as well, if the sizing for the array of arrays inferior dimension is runtime-generated, but that doesn't seem to be your question (yet). For now, the above should get you where you want to go.
Best of luck.
struct does not create a 2D array, struct creates a structure - a 'template' that unifies different data types and stores them as an 'unity' in memory
A 2D array is created by i.e. int 2Darray[3][4] = {{0,1,2},{8,9,10,11}};
A 2D array of a structure is created by i.e. struct Cars cars2Darray[10][10];
See this http://www.tutorialspoint.com/cprogramming/c_multi_dimensional_arrays.htm
To pass a 2D array to a function as argument one possible method is to use a pointer to the 0-element of the array i.e. 2D_array[0] (if the array is named 2D_array).
In the following the pointer 'ptr' points to the 0-element of the int-array '1D_array'
int 1D_array[8]= { 1, 2, 4, 8, 16, 32, 64, 128 };
int *ptr;
ptr = 1D_array;
The ptr = 1D_array stores the address of the 0th element of 1D_array in ptr, so ptr now points to the 0-th element of 1D_array
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int 1D_array[8]= { 1, 2, 4, 8, 16, 32, 64, 128 };
int *ptr;
int i;
ptr = 1D_array;
printf("The value, *ptr points to, is %d\n", *ptr);
printf("When applying *ptr+1 it points to %d\n", *(ptr+1));
printf("*(ptr+3) = %d\n", *(ptr+3));
printf("\n all elements of 1D_array : \n");
for(i=0; i<8; i++)
printf("element[%d]=%d \n", i, *(ptr+i));
return EXIT_SUCCESS;
}
As ptr now points to the 0th element of 1D_array you can use it to pass the array to a function.
For how to pass a 2D array to a function there are 3 methods (2 using pointers) see this Correct way of passing 2 dimensional array into a function

Assigning an address to a struct pointer array member in C

Having considerable trouble with some pointer arithmatic. I think I get the concepts (pointer variables point to a memory address, normal variables point to data) but I believe my problem is with the syntax (*, &, (*), *(), etc.)
What I want to do is build dynamic arrays of a custom struct (i.e. arrays of pointers to heap structs), and my interface provides two methods, "ad_to_obj_array" (which takes the object to add and the array which can be null for empty) and "obj_array_dustbin" (which just takes the array to dispose, also disposing of the contents, the heap objs). The former is rendered below.
The details of the objects are not important (and the struct has been renamed anyway) but my solution to the general problem is below, and I'd be grateful if you can spot the error. The compiler is complaining about an invalid lvalue, where I try and assign the address in the pointer on the RHS to the pointer value in an array of pointers to heap structs:
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))
obj* add_to_obj_array(obj* new_obj, obj* array)
{
int number_of_elements = 0;
if (array != NULL)
{
number_of_elements = NUM_ELEM(array);
}
obj* new_array = NULL;
/* note: I am expecting sizeof(new_obj) to return the size of an obj*
to go into the array of pointers. */
if ( NULL ==
(new_array = (obj*)malloc((number_of_elements + 1)* sizeof(new_obj))) )
{
/* memory request refused :( */
return NULL;
}
/* copy the old array pointers into the new array's pointer slots: */
int i;
for (i = 0; i < number_of_elements; i++)
{
&(new_array[i]) = &(array[i]);
}
/* add the new item to the end (assign pointer value directly): */
new_array[number_of_elements] = new_obj;
if (number_of_elements > 0)
{
free(&array);
}
return new_array;
}
Now, I have tried the following permutations of the offending line:
&(new_array[i]) = &(array[i]);
*(new_array[i]) = &(array[i]);
new_array[i] = &(array[i]);
and all give a compiler error of one sort or another. I am fairly sure that the right hand side is the address of the ith element of the old array, but how to I assign to the ith element of the new, when the elements of the array are pointers to structs?
EDIT - please note, the macro NUM_ELEM above DOES NOT WORK; it will always return 1. See #Merlyn Morgan-Graham's answer below for why.
Based on your description, you're starting off wrong, so by the time you get to copying things, nothing you can do is likely to work.
Right now, you've defined new_array (and, presumably, array) as a pointer to obj. The result looks like this:
In this case, you have a pointer to a dynamically allocated array of objects. When/if you expand the allocation, you'll need to copy all the objects themselves.
According to your description: "(i.e. arrays of pointers to heap structs)", what you want is an array of pointers. If you want to allocate that array of pointers automatically, your definition would look like:
obj *array[NUMBER];
My guess is that's not what you want though. Presumably, you want to allocate that array dynamically as well. That would look like this:
In this case, new_array and array will each need to be defined as a pointer to pointer to obj. You'd then allocate an array of pointers (i.e., pointers to as many objs as you want) and have each point point at an obj:
obj **new_array;
// allocate an array of pointers with space to point at more items:
new_array = malloc(sizeof(obj *) * new_elements);
// copy the pointers to the current items to the new array:
for (i=0; i<current_elements; i++)
new_array[i] = array[i];
The advantage of this is that when you do the copying, you only copy pointers, not the objects themselves. Especially with large objects, this can save a substantial amount of effort. The tradeoff is that using an element goes through two levels of indirection intead of one, so the reference may be slower (though rarely much slower, especially on a relatively high-performance processor).
As #rerun already pointed out, in either case you probably want to use realloc. In particular, this might be able to expand an allocation "in place", and avoid copying data as often. Of course, that's not guaranteed, but at least you're giving it a chance; if you malloc and copy every time, you eliminate even the possibility of that optimization.
You have two arrays doesn't new_array[i] = array[i] do what you need.
Have you looked at realloc as a possible solution.
Just assign the values across. new_array[i] = array[i].
The problem you may be running into is that, for obj* to actually be an array of pointers, obj must itself be a pointer type:
typedef struct
{
int value1;
} obj_pool;
typedef obj_pool* obj;
int main(int argc, char* argv[])
{
obj_pool pool1;
pool1.value1 = 5;
obj array[] = { &pool1 };
array[0]->value1 = 16;
return 0;
}
Another problem you'll run into once you get this compiling is that sizeof(array) == sizeof(obj*). NUM_ELEM(array) will always return the same value. This means you'll have to pass a size_t array_size parameter to your function.
in your code elements of the array are not pointers on the structure, they are structure objects. elements of the this array obj** array are pointers on the structure obj.
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))
void add_to_obj_array(obj* new_obj, obj** array)
{
int number_of_elements = 0;
if (array != NULL)
{
number_of_elements = NUM_ELEM(array);
}
// expand array with one more item
array = (obj**)realloc(array, (number_of_elements + 1) * sizeof(new_obj));
if (array == NULL )
{
/* memory request refused :( */
return;
}
// Put new item at the last place on the array
array[number_of_elements] = new_obj;
}
So here we used matrix (pointer on pointers of the obj structure). When we add new element we simply expand existing array for one place and on that place we put new structure object. There is no need to return value because we operate on the pointers of the objects, and all change is done on actual objects, not on their copies.

Resources