Creating an array of structs, creating to large of an array, C - c

I'm currently creating an array of structs, and when i initialize the array, it is starting with 8 elements in the struct, instead of 1. Why is it doing this? If more code is needed (but i doubt it as they are all seperate functions, i can post it if asked)
This is the relevant bits of code:
typedef struct {
int valid;
int row, col;
} Point;
typedef struct {
Point point;
int number;
char name;
char param[20];
char type[20];
} Agent;
int main(int argc, char **argv)
{
int steps;
int listSize = 0;
Agent *agentList = (Agent *) calloc(1, sizeof(Agent));
printf("%d size of agentList when initialised\n", sizeof(agentList));
if (argc != 4) {
error(SHOW_USAGE);
}
sscanf(argv[2], "%d", &steps);
if ((steps < 1)) {
error(BAD_STEPS);
}
readMap(argv[1]);
agentList = readAgentFile(argv[3], agentList);
print_agents(agentList);
return 0;

printf("%d size of agentList when initialised\n", sizeof(agentList));
This will give you the size of the agentList pointer which will most likely be four or eight in current systems.
Similarly, sizeof(*agentList) would simply give you the size of the structure pointed to by agentList but that's a single element of the array rather than the entire array.
There is no way to get from a pointer to the size of the array pointed at by it, simply because a pointer points at a single thing, not an array. By that, I mean it may well point to the first element of an array but that's not the same thing as pointing at an array. The distinction is subtle but important.
If you want to know the size of an array where the only thing you have is a pointer to it, you will have to remember it separately.

This here is not giving you the size of the array, but giving you the size of the pointer:
printf("%d size of agentList when initialised\n", sizeof(agentList));
It's not possible to determine the size of the array from the pointer, you need to store the size of the array separately and carry it around with the array.
This is why you will notice many functions in C will have both a pointer and a size argument.

Related

When Declaring a Double Pointer that is an array why is there no need to put brackets because it is an array of pointers?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** AllocateShoppingList(int numFoods);
char* AllocateItem();
int DetermineNumberOfCandy(char** list, int numFoods);
int main()
{
char** stringArray;// pointer to pointers
char* words; //pointer to char array
//1. ask the user how many foods are on their list
int foods;
printf("How many foods on the shopping list?\n");
scanf("%d", &foods);
//2. call the AllocateShoppingList function and store the result
stringArray = AllocateShoppingList(foods);
//3. for X times (user's previous input), call the AllocateItem function
// and store the result in the list of pointers (step 2)
for(int i =0;i < foods; i++){
words = AllocateItem();
stringArray[i] = words;}
//strcpy(stringArray[i],words); why not work?
//4. call the DetermineNumberOfCandy function, and print the result
printf("Candy appeared this many times: %d\n",DetermineNumberOfCandy(stringArray, foods));
//5. free up all of the pointers that are held by the shopping list
//6. free up the shopping pointer itself
free(words);
free(stringArray);
}
int DetermineNumberOfCandy(char** list, int numFoods)
{
//0. setup a counter variable
int counter = 0 ;
//1. for each pointer in the shopping list:
//1a. compare the string at the pointer's address to "candy"
for(int i =0; i< numFoods; i++)
if (strcmp(list[i],"candy")==0)
// why you dont have to dereference it
// this concept works with single pointers
// does it work with double or tripple pointers as long as it orignally points to the string?
counter++;
//1b. if it is candy, then tick up the counter variable
//2. return the counter variable
return counter;
}
char** AllocateShoppingList(int numFoods)
{
return calloc(numFoods, sizeof(char*));
//1. allocate memory that can hold X pointers (X = numFoods)
//2. return the memory address holding this pointer to pointers
}
char* AllocateItem()
{
char* wordPtr;
char word[100];
//1. get a word from the user that is max 100 characters
scanf("%s", word);
//2. determine how large the word actually is
wordPtr = calloc(strlen(word)+1,sizeof(char));
strcpy(wordPtr, word);
//3. allocate memory that is just enough to hold the word
return wordPtr;
//4. copy the user's word into the new memory location
//5. return the memory address holding the word
}
**For this code we had to get a shopping last and see print out how many times candy was in the shopping list and in order to do that we had to allocates enough memory to hold onto as many words (strings) as the user wants to have on their shopping list. Then, for each item, allocate just enough memory to store the word. **
This declaration right here for me doesn't make sense
**char** stringArray; **
From what I understand the double pointer is an array which element in the array contains a pointer to the string address.
Because of this I would think that we would have to declare the double pointer like:
char stringArray[]; **
something like this but that would not work.
So I wanted to know how the code knows it is an Array of pointers if we never put brackets
I tried declaring the double pointer with an array and could not get it to work nor could figure out if it was even possible.
Pointers are pointers, arrays are arrays. However, when an array in C is used in an expression or passed as a parameter to a function, it "decays" into a pointer to the first element of that array. This in turn enables things like a pointer arithmetic and the convenient use of the [] index operator.
This also means that in most contexts, a pointer to the first element can be used in place of an array. If we have an array of pointers char* arr[n]; then a char** can be used to point at the first item, and from there on the rest of the array.
So if you'd write a function like int DetermineNumberOfCandy(int numFoods, char* list[numFoods]); that's fine and valid C, but list "decays" into a pointer to the first element anyway, so it is 100% equivalent to
int DetermineNumberOfCandy(int numFoods, char** list);
Also you have misc bugs in your code.
Since AllocateItem is what allocates a valid memory location, the stringArray[i] in main() must be assigned to this memory location before it can be used. Because until then it is just an uninitialized pointer pointing at garbage. Therefore you can't strcpy(stringArray[i], words). Remember that the function did not just allocate a chunk of memory, but also filled it with valid data. So it is sufficient to set the pointer to point at that data, no need to copy anything.
The word variable doesn't fill any purpose, you could as well write this:
for(int i=0; i < foods; i++){
stringArray[i] = AllocateItem();
}
Similarly free(words) is wrong, this would only free the last allocated memory. Rule of thumb: for each malloc call you must have a corresponding free call! Therefore it should be:
for(int i=0; i < foods; i++){
free(stringArray[i]);
}
free(stringArray);
When you declare a variable like a string like this:
char str[10];
Your computer declares in fact a pointer but allocates enough memory to hold 10 characters automaticely. You will see that if you dereference it, you will get the first character of your string.
About your strcpy not working on line 20, if doesnt work because you created your i variable in a for loop and when you do that, the variable disapeers at the end of the loop so you are not able to use it nowhere into your code.
And about your line 40, you can use pointers in at least 2 deferent ways. First one is passing a variabe as a pointer in a function for you to dont have to return it at the end of a function like so:
int main()
{
int var = 0;
my_funct(&var);
//var = 1 now
}
void myfunct(int *var)
{
*var = 1;
}
Here you need to dereference it but if you allocated memory to your pointer, you can now use it as an array without dereferencing it.
Oh and here, you just free one pointer of the 2 in your stringarray. To free everything, try:
for(int i = 0; i < foods; i++) {
free(StringArray[i]);
}
free(StringArray);
Tell me if i didnt awnser to everything or if i was not clear enough

access to a member of a struct (pointer) with the use of double pointer

hey I am trying to create a program in which I am trying store elements from one array to another with the use of a pointer to pointer but the problem is that is caused undefined behavior I believe that the problem is that I do not pass the elements in members with a proper way
I know it is a vague way of doing this but It is in only for practising reasons
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student{
char *name;
int *number;
}T;
int main(void) {
char array[10][100]={"araaaa","bbgt","gffkghgh"};
T arr[10][100];
T *p;
T **p1;
p=&arr[0][0];
p1=&p;
int i=0;
for(i = 0 ; i < 3 ; i++)
{ p=arr[i];
strcpy((*p1)->name,array[i]);
}
/*******print_elements*************/
for(i = 0 ; i < 3 ; i++)
{ p=arr[i];
printf("\n the elements are %s",(*p1)-> name);
}
return 0;
}
When you do this:
strcpy ((*p1)->name, array[i]);
(*p1)->name is an uninitialised pointer. What happens, therefore, is in the lap of the gods.
The easiest fix is to modify your student structure such that name is a buffer, rather than a pointer. At the same time, change number to an int, rather than a pointer to an int::
typedef struct student{
char name [100];
int number;
} T;
If you want to keep name as a pointer then you have to allocate some memory before you store your string in it. This should work:
(*p1)->name = strdup (array[i]);
Don't forget to free the memory when done.
T is made of of two pointers, this first one points to a string of characters in memory.
arr is a 2D array that is allocated to store a total of 1000 T structures.
arr[i] would reference a 1D array of T structures within arr
*p1 would essentially be arr[i], since dereferencing p1 gives you p, which was just set to arr[i]. So, that is not a pointer to a T structure, but to an array of T structures. Forcing the cast will likely give you a reference to the first T structure in that row, however.
->name This value is never set. You allocated an array, but "name" is a pointer to memory, not an array of characters, so '->name' is undefined.
I think you need to change arr to be a single dimension array. You aren't using 90% of it.
And, you need to initialize every T struct in that array. You can use malloc or strdup, and then remember to free them all. Or, set the struct to use an array instead.

How to initiliaze a dynamic 2D array inside a struct in c?

I want to use a struct to contain some data and passing them between different functions in my program,this struct has to contain a dynamic 2D array (i need a matrix) the dimensions change depending on program arguments.
So this is my struct :
struct mystruct {
int **my2darray;
}
I have a function that read numbers from a file and has to assign each of them to a cell of the struct array.
I tried doing this :
FILE *fp = fopen(filename, "r");
int rows;
int columns;
struct mystruct *result = malloc(sizeof(struct mystruct));
result->my2darray = malloc(sizeof(int)*rows);
int tmp[rows][columns];
for(int i = 0;i<rows;i++) {
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &tmp[i][j]);
}
result->my2darray[i]=malloc(sizeof(int)*columns);
memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
}
But this is giving me a strange result : all the rows are correctly stored except for the first.
(I'm sure that the problem is not in the scanning of file).
While if i change the fourth line of code in this :
result->my2darray = malloc(sizeof(int)*(rows+1));
it works fine.
Now my question is why this happens?
Here's an answer using some "new" features of the language: flexible array members and pointers to VLA.
First of all, please check Correctly allocating multi-dimensional arrays. You'll want a 2D array, not some look-up table.
To allocate such a true 2D array, you can utilize flexible array members:
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
It will be allocated as a true array, although "mangled" into a single dimension:
size_t x = 2;
size_t y = 3;
array2d_t* arr2d = malloc( sizeof *arr2d + sizeof(int[x][y]) );
Because the problem with flexible array members is that they can neither be VLA nor 2-dimensional. And although casting it to another integer array type is safe (in regards of aliasing and alignment), the syntax is quite evil:
int(*ptr)[y] = (int(*)[y]) arr2d->flex; // bleh!
It would be possible hide all this evil syntax behind a macro:
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
Read as: if arr2d is a of type array2d_t* then access that pointer to get the flex member, then cast it to an array pointer of appropriate type.
Full example:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
int main (void)
{
size_t x = 2;
size_t y = 3;
array2d_t* arr = malloc( sizeof *arr + sizeof(int[x][y]) );
arr->x = x;
arr->y = y;
for(size_t i=0; i<arr->x; i++)
{
for(size_t j=0; j<arr->y; j++)
{
get_array(arr)[i][j] = i+j;
printf("%d ", get_array(arr)[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
Advantages over pointer-to-pointer:
An actual 2D array that can be allocated/freed with a single function call, and can be passed to functions like memcpy.
For example if you have two array2d_t* pointing at allocated memory, you can copy all the contents with a single memcpy call, without needing to access individual members.
No extra clutter in the struct, just the array.
No cache misses upon array access due to the memory being segmented all over the heap.
The code above never sets rows and columns, so the code has undefined behavior from reading those values.
Assuming you set those values properly, this isn't allocating the proper amount of memory:
result->my2darray = malloc(sizeof(int)*rows);
You're actually allocating space for an array of int instead of an array of int *. If the latter is larger (and it most likely is) then you haven't allocated enough space for the array and you again invoke undefined behavior by writing past the end of allocated memory.
You can allocate the proper amount of space like this:
result->my2darray = malloc(sizeof(int *)*rows);
Or even better, as this doesn't depend on the actual type:
result->my2darray = malloc(sizeof(*result->my2darray)*rows);
Also, there's no need to create a temporary array to read values into. Just read them directly into my2darray:
for(int i = 0;i<rows;i++) {
result->my2darray[i]=malloc(sizeof(int)*columns);
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &result->my2darray[i][j]);
}
}
In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.
When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)
int main(void)
{
struct mystruct result = {0};
result.my2darray = Create2D(5, 20);
if(result.my2darray)
{
// use result.my2darray
result.my2darray[0][3] = 20;// for simple example, but more likely in a read loop
// then free result.my2darray
free2D(result.my2darray, 5);
}
return 0;
}
Using the following two functions:
int ** Create2D(int c, int r)
{
int **arr;
int y;
arr = calloc(c, sizeof(int *)); //create c pointers (columns)
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
}
return arr;
}
void free2D(int **arr, int c)
{
int i;
if(!arr) return;
for(i=0;i<c;i++)
{
if(arr[i])
{
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.
int some_array[5][20] = {0};//init all elements to zero
Is what is commonly referred to in C an int array, also allowing access to each element via indexing. In actuality (Even though commonly referred to as an array.) it is not an array. The location of elements in this variable are stored in one contiguous location in memory.
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0... (~ 82 more)
But C maintains the locations such that they are all indexable as an 2D array.

How to return a char** in C

I've been trying for a while now and I can not seem to get this working:
char** fetch (char *lat, char*lon){
char emps[10][50];
//char** array = emps;
int cnt = -1;
while (row = mysql_fetch_row(result))
{
char emp_det[3][20];
char temp_emp[50] = "";
for (int i = 0; i < 4; i++){
strcpy(emp_det[i], row[i]);
}
if ( (strncmp(emp_det[1], lat, 7) == 0) && (strncmp(emp_det[2], lon, 8) == 0) ) {
cnt++;
for (int i = 0; i < 4; i++){
strcat(temp_emp, emp_det[i]);
if(i < 3) {
strcat(temp_emp, " ");
}
}
strcpy(emps[cnt], temp_emp);
}
}
}
mysql_free_result(result);
mysql_close(connection);
return array;
Yes, I know array = emps is commented out, but without it commented, it tells me that the pointer types are incompatible. This, in case I forgot to mention, is in a char** type function and I want it to return emps[10][50] or the next best thing. How can I go about doing that? Thank you!
An array expression of type T [N][M] does not decay to T ** - it decays to type T (*)[M] (pointer to M-element array).
Secondly, you're trying to return the address of an array that's local to the function; once the function exits, the emps array no longer exists, and any pointer to it becomes invalid.
You'd probably be better off passing the target array as a parameter to the function and have the function write to it, rather than creating a new array within the function and returning it. You could dynamically allocate the array, but then you're doing a memory management dance, and the best way to avoid problems with memory management is to avoid doing memory management.
So your function definition would look like
void fetch( char *lat, char *lon, char emps[][50], size_t rows ) { ... }
and your function call would look like
char my_emps[10][50];
...
fetch( &lat, &lon, my_emps, 10 );
What you're attempting won't work, even if you attempt to cast, because you'll be returning the address of a local variable. When the function returns, that variable goes out of scope and the memory it was using is no longer valid. Attempting to dereference that address will result in undefined behavior.
What you need is to use dynamic memory allocation to create the data structure you want to return:
char **emps;
emps = malloc(10 * sizeof(char *));
for (int i=0; i<10; i++) {
emps[i] = malloc(50);
}
....
return emps;
The calling function will need to free the memory created by this function. It also needs to know how many allocations were done so it knows how many times to call free.
If you found a way to cast char emps[10][50]; into a char * or char **
you wouldn't be able to properly map the data (dimensions, etc). multi-dimensional char arrays are not char **. They're just contiguous memory with index calculation. Better fit to a char * BTW
but the biggest problem would be that emps would go out of scope, and the auto memory would be reallocated to some other variable, destroying the data.
There's a way to do it, though, if your dimensions are really fixed:
You can create a function that takes a char[10][50] as an in/out parameter (you cannot return an array, not allowed by the compiler, you could return a struct containing an array, but that wouldn't be efficient)
Example:
void myfunc(char emp[10][50])
{
emp[4][5] = 'a'; // update emp in the function
}
int main()
{
char x[10][50];
myfunc(x);
// ...
}
The main program is responsible of the memory of x which is passed as modifiable to myfunc routine: it is safe and fast (no memory copy)
Good practice: define a type like this typedef char matrix10_50[10][50]; it makes declarations more logical.
The main drawback here is that dimensions are fixed. If you want to use myfunc for another dimension set, you have to copy/paste it or use macros to define both (like a poor man's template).
EDITa fine comment suggests that some compilers support variable array size.
So you could pass dimensions alongside your unconstrained array:
void myfunc(int rows, int cols, char emp[rows][cols])
Tested, works with gcc 4.9 (probably on earlier versions too) only on C code, not C++ and not in .cpp files containing plain C (but still beats cumbersome malloc/free calls)
In order to understand why you can't do that, you need to understand how matrices work in C.
A matrix, let's say your char emps[10][50] is a continuous block of storage capable of storing 10*50=500 chars (imagine an array of 500 elements). When you access emps[i][j], it accesses the element at index 50*i + j in that "array" (pick a piece of paper and a pen to understand why). The problem is that the 50 in that formula is the number of columns in the matrix, which is known at the compile time from the data type itself. When you have a char** the compiler has no way of knowing how to access a random element in the matrix.
A way of building the matrix such that it is a char** is to create an array of pointers to char and then allocate each of those pointers:
char **emps = malloc(10 * sizeof(char*)); // create an array of 10 pointers to char
for (int i = 0; i < 10; i++)
emps[i] = malloc(50 * sizeof(char)); // create 10 arrays of 50 chars each
The point is, you can't convert a matrix to a double pointer in a similar way you convert an array to a pointer.
Another problem: Returning a 2D matrix as 'char**' is only meaningful if the matrix is implemented using an array of pointers, each pointer pointing to an array of characters. As explained previously, a 2D matrix in C is just a flat array of characters. The most you can return is a pointer to the [0][0] entry, a 'char*'. There's a mismatch in the number of indirections.

Changes rows of the matrix

I have an array of structs. Actually, it is a 2d-array but an unusual 2d array.
I am allocating memory on stack:
#define MAX_VERTICES 5068
struct ARRAY_FIX {
int ele[MAX_VERTICES];
int size;
int first;
};
ARRAY_FIX C[MAX_VERTICES];
int main() {
//...
}
So, I need to replace one row with another one (actually, i need this operation to be performed for sorting rows by some criteria).
How is it possible to perform? As I understand, if I use this code:
С[i] = C[j];
In this code, the operator "=" will copy all array, won't it? I needn't it, I want to change the rows by changing the pointer
How can I do it?
You can use an array of pointers to struct ARRAY_FIX and just switch the pointers into the array.
I am allocating memory on stack.
An object declared at file scope is usually NOT on the stack.
In your case, each row is represented by struct ARRAY_FIX object. If you want to be able to work with these rows by using references (changing the order of rows by swapping pointers etc.), your 2D array must be stored in a way that allows you to do that.
Possible solution is to change your 2D array to an array of pointers to struct ARRAY_FIX so that when you call С[i] = C[j]; only the reference (address of your object) is copied, not an object itself.
Also note, that you should worry about the performance and try to make your program faster only when it's really needed. It's much easier to make a correct program fast than it's to make a fast program correct.
as said before
Possible solution is to change your 2D array to an array of pointers
to struct ARRAY_FIX
here after how to do it:
#define MAX_VERTICES 5068
struct ARRAY_FIX {
int ele[MAX_VERTICES];
int size;
int first;
};
ARRAY_FIX *C[MAX_VERTICES];
int main() {
int i;
ARRAY_FIX *p;
//...
for (i=0;i<MAX_VERTICES;++i)
{
C[i] = malloc (sizeof(ARRAY_FIX ));
//...
}
//...
p = C[1];
C[1] = C[2];
C[2] = p;
//...
}

Resources