Create N elements of struct after input N - c

How can i create N elements of this struct after the input N?
typedef struct cat{
int code;
int age;
float weight;
enum {kibbles,canned_food,tuna_fish}food;
} cats;
int n,i;
printf("Insert a number: ");
scanf("%d",&n);
for(i=0;i<n;i++){
....
}
I want to create N cats (named cat1,cat2 etc..)

Make a function to input a single struct cat
struct cat inputsinglecat(void);
After you know how many cats you need, get the amount of memory required
struct cat *memcat;
memcat = malloc(n * sizeof *memcat);
if (memcat == NULL) exit(EXIT_FAILURE);
Then, to enter cats, use a loop and the function defined above
for (int k = 0; k < n; k++) {
memcat[k] = inputsinglecat();
}
Don't forget to release the memory when you don't need it anymore
free(memcat);

You can either do it statically, by creating an array of cats:
cats myCatsArray[10];
or dynamically, using malloc or calloc (the latter defined as void *calloc(size_t nitems, size_t size)):
cats *myCatsArray = calloc( 10, sizeof (cats)):
Just avoid the static definition as a local variable of a function, in order to avoid to occupy to much memory in the stack. In case of dynamic allocation you have to remember to free() the structs as soon as you don't need them anymore.
After allocating all the N cats you need, you are able to populate their fields according to your requirements.
In both cases you can access an element (lets say the sixth one) in this way
int myCode = myCatsArray[5].code;

Related

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.

Make a new struct variable when users needs it

I'm just getting started with C, and having issues with struct. For instance I have:
struct student {
int id;
char name[25]
};
I want the user to add as many students as he needs:
int count = 0;
while (stop == 0){
struct student count
scanf("%d", count.id);
scanf("%s", count.name);
scanf("%d", stop);
}
It looks like I've to create struct student count (where count is a number) and keep creating these. So, I would like to create something like struct student 0, then struct student 1 and so on, so I can reference each student by it's count or number.
How would I get something like this to work?
This will automatically allocate memory when user requests it. It starts from a dimension of 1, up to virtually infinite (actually, up to the space available in RAM).
Of course if you want, you can change the initial size of size, as well as the growth rate of the array.
// Example program
#include <stdio.h> /* printf, scanf */
#include <stdlib.h> /* for realloc, malloc */
// Supposing student is defined like this:
struct student
{
int id;
char name[25];
};
int main()
{
int stop = 0;
int count = 0;
int size = 0;
// Using an array of students
size = 1;
struct student* students = malloc(size * sizeof(struct student));
while (stop == 0)
{
if(count >= size)
{
size ++;
students = realloc (students, size * sizeof(struct student));
if (students == NULL)
{
printf ("Failed to allocate more memory.\n");
return 0;
}
}
scanf("%d", &(students[count].id));
scanf(" %24[0-9a-zA-Z ]", &(students[count].name));
scanf("%d", &stop);
count = count + 1;
}
int i = 0;
for (i = 0; i < count; ++i)
printf("%d => %d %s\n", i, students[i].id, students[i].name);
}
I think you would like to create multiple instances of the struct in your first code sample for each user that is entered in the console, handled by the while-loop.
The easiest way to achieve this, is to use an array. I suggest you to first use an array with a fixed size, that means that you specify the array size in your code. This array will allow you to add as many student instances into it as the array size you've specified.
A simple example would be something like this:
// Define the student struct
struct student {
int id;
char name[25];
};
// ...
// Create an array with a fixed size to put the students in, and define a counter
struct student students[128];
int count = 0;
while(stop == 0){
// Create the struct to fill
struct student newStudent;
// Fill the struct with the user supplied data
scanf("%d", newStudent.id);
scanf("%s", newStudent.name);
scanf("%d", stop);
// Add the struct to the array, and increase the count afterwards
students[count++] = newStudent;
}
In the above example, I've added an array with a fixed size of 128, which you can change to whatever size you'd like. In the while-loop, an instance of a new struct is made, which is similar to before. This struct is being filled afterwards with data fed from the console. At the end of the while-loop the struct instance is added to the array of students. This will give you an array of all the students you've entered.
There is a downside to this solution however, and that's that in most cases, much more memory is consumed than is really used. This is because for the computer, it feels like 128 whole instances (or any other array size if specified) are stored in RAM, this can be quite expensive if only two instances will be really used. Also, like I said earlier, make sure to keep in mind that fixing the array size limits the amount of entries, this can also have a negative effect on your code. If you don't want to have these consequences, you may want to take a look at the solution described bellow.
You can make the size of the array dynamic, this is a little more advanced. If you'd like to achieve something like this, make sure to take a look at memory allocation functions, like Sourav Ghosh pointed out in a comment. You may also want to take a look at the code-example Michael made.
I hope this helps to solve the problem you're having. Happy coding!

How do you use malloc to allocate space for an array of structures?

I'm currently working on dynamically allocating my array of structures and I'm unsure how to continue. This is my structure:
struct Word_setup
{
char word[M];
int count;
} phrase[N];
I know malloc returns a pointer to a block of memory, but I'm not sure how this works when it comes to an array of structures.
If anyone could please clarify that would be much appreciated!
Probably you meant:
struct Word_setup {
char word[M];
int count;
};
It's a good idea to avoid defining variables in the same line as a struct definition anyway, to help with code readability.
Then you can allocate an array of these:
int main()
{
struct Word_setup *phrase = malloc(N * sizeof *phrase);
// use phrases[x] where 0 <= x < N
phrase = realloc(phrase, (N+5) * sizeof *phrase);
// now can go up to phrases[N+4]
free(phrase);
}
Of course you should check for failure and abort the program if malloc or realloc returns NULL.
If you also want to dynamically allocate each string inside the word then there are a few options; the simplest one to understand is to change char word[M] to char *word; and each time you allocate a phrase, write the_phrase.word = malloc(some_number); . If you allocate an array of words you'll need to loop through doing that for each word.
I suppose that N and M is a compile-time known constants. Then just use sizeof, .e.g.
struct Word_setup*ptr = malloc(sizeof(struct Word_setup)*N);
Maybe you want a flexible array member. Then, it should always be the last member of your struct, e.g.
struct Word_setup {
int count;
unsigned size;
char word[]; // of size+1 dimension
};
Of course it is meaningless to have an array of flexibly sized structures -you need an array of pointers to them.

Array of struct implementation in C

I need some ideas on my array of struct implementation. This is what I have in my structs. I plan on making SHAPES an array because I will have multiple SHAPES. Each shape will have multiple x and y coordinates. Because of this I'm not sure if should make a linked list or not. The purpose of the start and finish is I will eventually be running a search algorithm after I get my shapes right.
struct START
{
int x;
int y;
};
struct END
{
int x;
int y;
};
struct SHAPES
{
int x [100];
int y [100];
int *link;
};
struct DISTANCE
{
int distance_traveled;
int distance_to_finish;
};
I was reading this and was wondering if I needed to malloc or calloc my structs as I create them. If so why and if not why? Malloc and calloc are always confusing to me.
How do you make an array of structs in C?
int main(int argc, char *argv[])
{
//Is it better to make these pointers?
struct START start;
struct END end;
struct SHAPES shapes[100];
while(fgets(line, 80, fp) != NULL)
{
//I have a very annoying issue here, I don't know the size of the lines.
//If there are more values I want to increment the x[] and y[] array but NOT the
//shapes array. I can only think of one way to deal with this by putting a bunch of
//variables in the sscanf. I discovered putting sscanf on the next line didn't do what
//I was hoping for.
sscanf(line, "%d%*c %d%*c ", &shapes[i].x[i] , &shapes[i].y[i] );
printf(" line is: %s \n", line);
sscanf(line, "%d%*c %d%*c ", &x1_main , &y1_main );
printf(" line is: %s \n", line);
printf(" shapes[i].x[i] is: %d \n", shapes[i].x[i]);
printf(" shapes[i].y[i] is: %d \n", shapes[i].y[i]);
printf(" x1_main is: %d \n", x1_main);
printf(" y1_main is: %d \n", y1_main);
i++;
memset(line, 0, 80);
}
}
This is what my file looks like. Adding the %*c seemed to handle the commas and semicolons appropriately.
10, 4
22, 37
22, 8; 2, 0; 3, 6; 7, 8; 5, 10; 25, 2
1, 2
I got that idea from here.
https://www.daniweb.com/software-development/c/threads/334515/reading-comma-separated-values-with-fscanf
First of all, you might want to consider something like this:
struct point {
int x;
int y;
};
so you can use a struct point data structure (array) instead of two separate data structures for x and y. Using it like this should also speed up access to the points, since their coordinates are next to each other in memory. Otherwise you will have x somewhere in the x array and y somewhere in the y array.
The choice of the data structure to store the points depends on your usage. If you need to address points directly, a linked list may be a bad choice. If you always access all points in a linear order, it is fine. However, consider that a singly linked list will add 8 bytes per point for the next pointer. A doubly linked list will use another 8 bytes for prev (assuming 64-bit arch that is; sizeof(pointer) in general). I assume, that you create x[100] and y[100] to make sure you have enough space. You might be better off using a dynamic array (the ADT) e.g. glib's GArray after all. It will grow as big as you need it without you doing anything.
For malloc vs calloc: it doesn't really matter. A call to calloc is basically a malloc followed by a
memset(ptr, 0, sizeof(mallocd area);
i.e. the memory is zeroed; cf manpage calloc. If you initialize the memory directly you may not need to do this.
A struct with no pointer members
If your struct has no pointer members, such as:
typedef struct {
int a;
int b;
} DEMO;
Then you can simply declare an array instance of a typedef struct like this:
DEMO demo[10];// instance of array of 10 DEMO
Example, struct with Pointer members
If you have a pointer in the list of members:
#define SIZE_STR 20
typedef struct {
int a;
int b;
char *str;//pointer, will require memory allocation
} DEMO;
DEMO demo[10];// instance of array of 10 DEMO
int main(void)
{
int i;
for(i=0;i<10;i++)//create memory for each instance of char * in array of DEMO
{
demo[i].str = malloc(SIZE_STR);
}
return 0;
}
Don't forget to free() all instances of malloc'ed memory.
Dynamically allocate array of struct
If you need to dynamically allocate memory for a struct:
typedef struct {
int a;
int b;
} DEMO;
DEMO demo, *pDemo;// create a pointer to DEMO
In a function, main() for example:
int main(void)
{
pDemo = &demo;
pDemo = malloc(sizeof(DEMO)*10);//provides an array of 10 DEMO
return 0;
}
Again, don't forget to free() all instances of malloc'ed memory.

Dynamic Memory storage issue after realloc - C

For an assignment at school, we have to use structs to make matrices that can store a infinite amount of points for an infinite amount of matrices. (theoretical infinite)
For the assignment I decided to use calloc and realloc. How the sizes for the matrix go is: It doubles in size every time its limit is hit for its points (so it starts at 1, then goes to 2, then 4 and so on). It also doubles in size every time a matrix is added as well.
This is where my issue lies. After the initial matrix is added, and it goes to add the second matrix name and points, it gives me the following:
B???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
B is the portion of it that I want (as I use strcmp later on), but the ? marks are not supposed to be there. (obviously)
I am not sure why it is exactly doing this. Since the code is modular it isn't very easy to get portions of it to show exactly how it is going about this.
Note: I can access the points of the matrix via its method of: MyMatrix[1].points[0].x_cord; (this is just an example)
Sample code that produces problem:
STRUCTS:
struct matrice {
char M_name[256];
int num_points[128];
int set_points[128];
int hasValues[1];
struct matrice_points * points;
} * MyMatrix;
struct matrice_points {
int set[1];
double cord_x;
double cord_y;
};
Setup Matrix Function:
void setupMatrix(){
MyMatrix = calloc(1, sizeof(*MyMatrix));
numMatrix = 1;
}
Grow Matrix Function:
void growMatrix(){
MyMatrix = realloc(MyMatrix, numMatrix * 2 * sizeof(*MyMatrix));
numMatrix = numMatrix * 2;
}
Add Matrix Function which outputs this problem after growing the matrix once.
void addMatrix(char Name, int Location){
int exists = 0;
int existsLocation = 0;
for (int i = 0; i < numMatrix; i++){
if (strcmp(MyMatrix[i].M_name, &Name) == 0){
exists = 1;
existsLocation = i;
}
}
*MyMatrix[Location].M_name = Name;
printf("Stored Name: %s\n", MyMatrix[Location].M_name);
*MyMatrix[Location].num_points = 1;
*MyMatrix[Location].set_points = 0;
*MyMatrix[Location].hasValues = 1;
MyMatrix[Location].points = calloc(1, sizeof(*MyMatrix[Location].points));
}
void addMatrix(char Name, int Location)
char Name represents a single char, i.e. a integer-type quantity. char is just a number, it's not a string at all.
When you do this:
strcmp(..., &Name)
you're assuming that the location where that one character is stored represents a valid C string. This is wrong, there is no reason why this should be the case. If you want to pass a C string to this function, you will need to declare it like this:
void addMatrix(char *Name, int Location)
Then you need to copy that C string into the appropriate place in your matrix structure. It should look like:
strncpy(... .M_name, Name, max_number_of_chars_you_can_store_in_M_Name);
Also these field definitions are strange in your struct:
int num_points[128];
int set_points[128];
int hasValues[1];
This means that your struct will contain an array of 128 ints called num_points, another array of 128 ints calls set_points, and an array of one int (strange) called hasValues. If you only need to store the count of total points and set points, and a flag indicating whether values are stored, the definition should be:
int num_points;
int set_points;
int hasValues;
and correct the assignments in your addMatrix function.
If you do need those arrays, then your assignments as they are are wrong also.
Please turn on all warnings in your compiler.
Try adding '\0' to the end of your data.
*MyMatrix[Location].M_name = Name;
You're copying a single character here, not a string. If you want a string, Name should be defined as char *, and you should be using strcpy.

Resources