Passing an Array of Structures - c

How can I pass an array of structures?
So far I have this which is global:
typedef struct _line
{
float val1;
int val2;
} line;
Then I read data from a file into this structure
struct _line* read_file()
{
typedef struct _line *Lines
Lines *array = malloc(num_lines * sizeof(Lines));
//read values into structures here
Then I fill up the structures in the array with values. If I do printf("%d", (*array[1]).val1); I get the right value here in this particular method
Then I return the array like so
return *array
But when I do so, only the 0th structure reads correctly in the method I returned to. Reading the 1st element just prints random values. What am I doing incorrectly?

You should not dereference the array when you return it1, it's actually of incompatible type with the function return type, just
return array;
also, check that array != NULL after malloc() before reading the values, and you don't really need the typedef it makes your code a bit confusing.
If your code compiled which I doubt, then you don't have warnings enabled in your compiler command, enable them so you can prevent this kind of issue.
(1) *array is equivalent to array[0].

Expanding on my comments, your code (as you describe and show it) you have undefined behavior:
This is because you allocate an array of pointers, but you apparently do not allocate the pointers in that array. So when you dereference a pointer (which you haven't allocated and whose value is indeterminate and so will point to a seemingly random location) you have this undefined behavior.
Instead of using a type-alias like Line use the structure name, like
struct _line *array = malloc(num_lines * sizeof(*array));
That will allocate num_lines structures (instead of pointers), then you use it like a normal array, without the pointer dereferencing
array[x].val1 = something;
And you of course return that pointer array as-is:
return array;

Related

Why does this example of pointer dereferencing work?

I have some code, and it works, and I don't understand why. Here:
// This structure keeps the array and its bookkeeping details together.
typedef struct {
void** headOfArray;
size_t numberUsed;
size_t currentSize;
} GrowingArray;
// This function malloc()'s an empty array and returns a struct containing it and its bookkeeping details.
GrowingArray createGrowingArray(int startingSize) { ... }
// Self-explanatory
void appendToGrowingArray(GrowingArray* growingArray, void* itemToAppend) { ... }
// This function realloc()'s an array, causing it to double in size.
void growGrowingArray(GrowingArray* arrayToGrow) { ... }
int main(int argc, char* argv[]) {
GrowingArray testArray = createGrowingArray(5);
int* testInteger = (int*) malloc(1);
*testInteger = 4;
int* anotherInteger = (int*) malloc(1);
*anotherInteger = 6;
appendToGrowingArray(&testArray, &testInteger);
appendToGrowingArray(&testArray, &anotherInteger);
printf("%llx\n", **(int**)(testArray.headOfArray[1]));
return 0;
}
So far, everything works exactly as I intend. The part that confuses me is this line:
printf("%llx\n", **(int**)(testArray.headOfArray[1]));
By my understanding, the second argument to printf() doesn't make sense. I got to mostly by trial and error. It reads to me as though I'm saying that the second element of the array of pointers in the struct is a pointer to a pointer to an int. It's not. It's just a pointer to an int.
What does make sense to me is this:
*(int*)(testArray.headOfArray[1])
It's my understanding that the second element of the array of pointers contained in the struct will be fetched by the last parenthetical, and that I then cast it as a pointer to an integer and then dereference that pointer.
What's wrong with my understanding? How is the compiler interpreting this?
My best guess is that your appendToGrowingArray looks something like this:
void appendToGrowingArray(GrowingArray* growingArray, void* itemToAppend) {
growingArray->headOfArray[growingArray->numberUsed++] = itemToAppend;
}
though obviously with additional logic to actually grow the arrow. However the point is that the itemToAppend is stored in the array pointed to by headOfArray.
But, if you look at your appendToGrowingArray calls, you are passing the addresses of testInteger and anotherInteger -- these are already pointers to integers, so you are storing pointers to pointers to integers in your headOfArray when you really intend to store pointers to integers.
So, when you consider testArray.headOfArray[1], it's value is the address on main's stack of the variable anotherInteger. When you dereference it the first time, it now points to the address of the buffer returned by the second malloc call that you stored in anotherInteger. So, it's only when you deference it a second time that you get to the contents of that buffer, namely the number 6.
You probably want to write:
appendToGrowingArray(&testArray, testInteger);
appendToGrowingArray(&testArray, anotherInteger);
instead.
(As noted in a comment, you also should fix your mallocs; you need more than 1 byte to store an integer these days!)

Handling an array of pointers

I'm attempting to create a struct that has an array of char pointers as one of its members and am having trouble attempting to set/access elements of the array. Each char pointer is going to point to a malloc'd buffer. This is the struct currently.
struct rt_args {
long threadId;
char (*buffers)[];
FILE* threadFP;
};
And when I attempt to access an element of buffers via
char *buffer = malloc(100);
struct rt_args (*rThreadArgs) = malloc( sizeof(long) +
(sizeof(char *) * (numThreads)) +
sizeof(FILE*)
);
rThreadArgs->buffers[0] = buffer;
I get the error "invalid use of array with unspecified bounds". I don't know what the size of the array is going to be beforehand, so I can't hardcode its size. (I've tried de-referencing buffers[0] and and adding a second index? I feel as though its a syntactical error I'm making)
You can't have arrays without a size, just like the error message says, at least not n the middle of structures. In your case you might think about pointers to pointers to char? Then you can use e.g. malloc for the initial array and realloc when needed.
Something like
char **buffers;
Then do
buffers = malloc(sizeof(buffers[0]) * number_of_pointers_needed);
Then you can use buffers like a "normal" array of pointers:
buffers[0] = malloc(length_of_string + 1);
strcpy(buffers[0], some_string);
char (*buffers)[SIZE];
declares buffers as a pointer to char array not the array of pointers. I think you need this
char *buffers[SIZE];
NOTE: Flexible array member can be used only when it is the last member of the structure.

Freeing a pointer in a structure referenced by a pointer

I have a pointer to several structures that have been allocated memory via:
STRUCTNAME *ptr;
ptr = (STRUCTNAME *)malloc(sizeof(STRUCTNAME)*numberOfStructs);
The structures are accessed via a offset like so:
(ptr + i)->field;
The structures have 2 fields that are character pointers as follows:
typedef struct
{
char *first;
char *second;
}STUCTNAME;
These fields are allocated memory as follows:
(ptr + i)->first = (char *)malloc(strlen(buffer));
This appears to work but when I try to free the pointers within the structures I get a segmentation fault 11 when I do this:
free((prt + i)->first);
Help?
Notes:
buffer is a character array. Offsetting a pointer by a integer should increment the pointer by the size of what it is pointing to times the integer correct?
Here is a link to my full source code. I have not written some of the functions and I am not using the freeAllpointers and printAll yet.
https://drive.google.com/file/d/0B6UPDg-HHAHfdjhUSU95aEVBb0U/edit?usp=sharing
OH! Thanks everyone! Have a happy Thanksgiving! =D (If you're into that kinda stuff)
In case, you don't initialize all those members in that piece of code, you're not showing us:
Allocate the struct storage (STRUCTNAME*) with calloc(), so that all allocated memory, namely firstand second are zero at the beginning. Passing NULL to free() will result in a no-op. Passing any wild (garbage) pointer to free() may cause a segmentation fault.
To detect a double-free, set ptr[i].first = NULL; after free(ptr[i].first); as a defensive measure for testing.
Notes: buffer is a character array. Offsetting a pointer by a integer
should increment the pointer by the size of what it is pointing to
times the integer correct?
Yes, except for void* on those compilers, which don't define sizeof(void), which is defined to have undefined behavior, to a value > 0: What is the size of void?
Edit:
void makeReviews(FILE *input, REVIEW *rPtr, int numReviews) <-- This does NOT return the new value of rPtr. In main(), it will remain NULL.
Do something like this:
REVIEW* makeReviews(FILE *input, int numReviews);
//...
int main(){
//...
rPtr = makeReviews(input,numReviews);
//...
}
or
void makeReviews(FILE** input,REVIEW** rPtrPtr,int numReviews){
REVIEW* rPtr = *rPtrPtr;
//...
*rPtrPtr = rPtr;
}
//...
int main(){
//...
makeReviews(input,&rPtr,numReviews);
//...
}
fgets(cNumReviews, sizeof(cNumReviews), input); <-- Perhaps, you could use something like fscanf().

memcpy-ing to a feild of a struct pointer in c

I am having trouble with struct pointers....Here are two examples in my code that are essentially doing the same thing except dsp is not a pointer and InMemory[Idx] is a pointer, how to I use memcpy in the pointer case?
my_struct* InMemory[SIZE]
//works prints: tmp3:local_file (file name)
memcpy(dsp.result.list[i].owner_name,req.file_name,256);
char tmp3[256];
memcpy(tmp3,dsp.result.list[i].owner_name,256);
printf("tmp3:%s\n",tmp3);
//doesn't work, prints: tmp:_____<---nothing! ??
//I am trying to copy the result from above into a field of the struct pointer array
char tmp2[256];
memcpy(InMemory[Idx]->filename,dsp.result.list[i].owner_name,256);
memcpy(tmp2,InMemory[Idx]->filename,256);
printf("tmp:%s\n",tmp2);
From your code, you have not allocated member elementes of InMemory
for (i=0;i<SIZE;i++)
{
// allocate elements here
InMemory[i]->filename = malloc(....)
// other allocations
}
// now use memcpy

initialize a global 2-dimensional C array of integers at run time

I need to store an array of point (x,y). I read the points from a file, and the number of points are not constant, but i can get it at the first line of the file. So i write a procedure load() to loading the points from the file and store them in a global array. It doesn't work.
My code:
int *array[][]; // this is a pointer to a 2-dimensional array??
void load(){
..
int tempArray[2][n]; //n is the first line of the file
..
array = tempArray;
}
You're trying to return a pointer to memory that is local to the function that defines the variable. Once that function stops running ("goes out of scope"), that memory is re-used for something else, so it's illegal to try and reference it later.
You should look into dynamic allocation, and have the loading function allocate the needed memory and return it.
The function prototype could be:
int * read_points(const char *filename, size_t *num_points);
Where filename is of course the name of the file to open, num_points is set to the number of points found, and the returned value is a pointer to an array holding x and y values, interleaved. So this would print the coordinates of the first point loaded:
size_t num_points;
int *points;
if((points = load_points("my_points.txt", &num_points)) != NULL)
{
if(num_points > 0)
printf("the first point is (%d,%d)\n", points[0], points[1]);
free(points);
}
This declaration of yours does not work:
int *array[][]; // this is a pointer to a 2-dimensional array??
First, it is trying to declare a 2D array of int *. Second, when you declare or define an array, all dimensions except the first must be specified (sized).
int (*array)[][2]; // This is a pointer to a 2D array of unknown size
This could now be used in a major variant of your function. It's a variant because I misread your question at first.
void load(void)
{
...
int tempArray[n][2]; // Note the reversed order of dimensions!
...
array = &tempArray;
...there must be some code here calling functions that use array...
array = 0;
}
Note that the assignment requires the & on the array name. In the other functions, you'd need to write:
n = (*array)[i][j];
Note, too, that assigning the address of a local array to a global variable is dangerous. Once the function load() returns, the storage space for tempArray is no longer valid. Hence, the only safe way to make the assignment is to then call functions that reference the global variable, and then to reset the global before exiting the function. (Or, at least, recognize that the value is invalid. But setting it to zero - a null pointer - will more nearly ensure that the program crashes, rather than just accessing random memory.
Alternatively, you need to get into dynamic memory allocation for the array.
Your question actually is wanting to make a global pointer to a VLA, variable-length array, where the variable dimension is not the first:
int tempArray[2][n]; // Note the reversed order of dimensions!
You simply can't create a global pointer to such an array.
So, there are multiple problems:
Notation for pointers to arrays
Initializing pointers to arrays
Assigning global pointers to local variables
You can't have global pointers to multi-dimensional VLAs where the variable lengths are not in the first dimension.
You should minimize the use of globals.
A more elegant version might go like this:
typedef struct point_ { int x; int y; } point;
point * create_array(size_t n)
{
return calloc(n, sizeof(point));
}
void free_array(point * p)
{
free(p);
}
int main()
{
size_t len = read_number_from_file();
point * data = create_array(len);
if (!data) { panic_and_die(); }
for (size_t i = 0; i != len; ++i)
{
/* manipulate data[i].x and data[i].y */
}
free_array(data);
data = 0; /* some people like to do this */
}
You are trying to assign an array but in C arrays cannot be assigned.
Use memcpy to copy one array to another array. Arrays elements in C are guaranteed to be contiguous.
int bla[N][M] = {0};
int blop[N][M];
/* Copy bla array to blop */
memcpy(blop, bla, sizeof blop);

Resources