How to initialize a struct into a pointed struct - c

Namaste! I want to initialize my struct array position 0 myList.items[0] with a pointer to my item struct, but it prints out jibberish on the relevant positions when I print it out from my print function. It changes what was previously initialized (for test) so I know it works partially, but what's causing the bad output and what should be changed?
Before:
----My Shopping list---------
1 - Chocolate 40 100g
2 - Fishsauce 9 l
After:
----My Shopping list---------
1 - c┴®¶²` 128565603 ■   lüIv
2 - Fishsauce 9 l
typedef struct{
char name[20];
int amount;
char amountType[10];
}item;
typedef struct{
item *items[5];
int length;
}list;
int addItemToList(list *myList);
main(void)
{
list myList;
myList.length = 0;
for(int i; i<5;i++)
{
myList.items[i] = NULL;
}
addItemToList(&myList);
return 0;
}
int addItemToList(list *myList)
{
item newItem = {"Potatoes",2, "kg"};
myList->items[myList->length]=&newItem; //Something wrong here?
myList->length++;
printf ("Added [%s %i %s] as #%i.", newItem.name, newItem.amount,newItem.amountType, myList->length);
return 0;
}

This:
int addItemToList(list *myList)
{
item newItem = {"Potatoes",2, "kg"};
That allocates newItem on the stack. That means the memory for it will go away when addItemToList is completed, so &newItem will be pointing to gibberish later. It will be fine while still running code in addItemToList, but then after that the memory contents will be replaced in any further functions that are called.
You can either use malloc to allocate some memory for newItem, or you can allocate newItem on the stack in your main function and pass the pointer to newItem to any other called functions.

You cannot initialize a struct on the stack and then pass the pointer to that struct to a different struct that lives longer than that stack frame is open. Once the function returns, the stack frame where your item was allocated will close and the assigned values to the fields will be gone.
You need an initializer function with a heap allocated struct like this:
item* item_new(const char* name, int amount, const char* amountType);
Then your initialization function should:
call Malloc for the size of struct,
Copy the name and amountType strings to the struct.
copy the amount to the struct.
Then you can do this: myList->items[myList->length]=newItem;, where newItem is created by your init function.

You are mixing stack and heap memory, I rewriten it for you, it should give you some sense what went wrong. Also always free allocated memory its no java:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char name[20];
int amount;
char amountType[10];
}item;
typedef struct{
item *items[5];
int length;
}list;
int addItemToList(list *myList);
int main(void)
{
list myList;
myList.length = 0;
for(int i; i<5;i++)
{
myList.items[i] = 0;
}
addItemToList(&myList);
for(int i; i<myList.length; i++)
{
free(myList.items[i]);
}
return 0;
}
int addItemToList(list *myList)
{
item* newItem = malloc(sizeof(item));
strcpy(newItem->name, "Potatoes");
newItem->amount = 2;
strcpy(newItem->amountType, "kg");
myList->items[myList->length++] = newItem; //Something wrong here?
printf ("Added [%s %i %s] as #%i.\n", newItem->name, newItem->amount, newItem->amountType, myList->length);
return 0;
}

Related

failing freeing dynamic struct array in c

I'm having some problem with freeing dynamic struct array and I can't understand why.
first of all there is this struct:
typedef struct
{
char name[LEN];
char address[MAX];
} Airport;
And the constructor I made for this struct isn't using allocation for this struct building.
sec of all there is this struct:
typedef struct
{
Airport* airports;
int maxAPS;
int currentAPS;
} AirportManager;
//constructor
void addAirport(AirportManager* pAirportManager)
{
if (pAirportManager->maxAPS == pAirportManager->currentAPS)
{
pAirportManager->maxAPS++;
pAirportManager->airports = (Airport*)realloc(pAirportManager->airports, sizeof(Airport)*pAirportManager->maxAPS);
//pAirportManager->airports[pAirportManager->currentAPS] = *(Airport*)malloc(sizeof(Airport));
}....
and when I'm ending my program and want to free the AirportManager with the following code:
void freeAirportManager(AirportManager* pAirportManager)
{
for (int i = 0; i < pAirportManager->currentAPS; i++)
free(&pAirportManager->airports[i]);
free(pAirportManager->airports);
}
I've debuged this one and all the parameters are just fine but after one run in the loop the program exits, what should I change in the free function ?
do I need the marked line in the constructor ? I just added this on thinking it might help, but seems to not work as well... do I need to free only the array itself ?
for (int i = 0; i < pAirportManager->currentAPS; i++)
free(&pAirportManager->airports[i]);
You need only to free pAirportManager->airports. You do not have pointer to pointer here.
So instead of those two lines:
free(pAirportManager->airports);
I would use flexible array member instead of pointer.
typedef struct
{
char name[LEN];
char address[MAX];
} Airport;
typedef struct
{
size_t maxAPS;
size_t currentAPS;
Airport airports[];
} AirportManager;
For sizes use size_t type instead of int

Assign int array to in pointer in struct

I have created below C struct.
typedef struct KnightsMartSale {
char firstName[21];
char lastName[21];
int numItemsOnList;
int *itemsPurchased; // array of item numbers
struct KnightsMartSale *next;
} KMSale;
Here is it possible to assign int array to the int *itemsPurchased pointer?
If it is possible how print the values?
I'd allocate memory according to the size of the array you want to copy into itemsPurchased and also "remember" the number of possible items in numItemsOnList.
So suppose you have a given array of ints, let's say myArray, then the code for copying and printing could look as follows:
typedef struct KnightsMartSale {
char firstName[21];
char lastName[21];
int numItemsOnList;
int *itemsPurchased; // array of item numbers
struct KnightsMartSale *next;
} KMSale;
int main() {
KMSale kmsale;
int myArray[] = { 20,30,40,50 };
kmsale.numItemsOnList = sizeof(myArray)/sizeof(myArray[0]);
kmsale.itemsPurchased = calloc(kmsale.numItemsOnList,sizeof(int));
memcpy(kmsale.itemsPurchased,myArray,kmsale.numItemsOnList*sizeof(int));
for (int i=0; i<kmsale.numItemsOnList; i++) {
printf("item #%d: %d\n",i,kmsale.itemsPurchased[i]);
}
// kmsale not needed any more, free memory:
free(kmsale.itemsPurchased);
}
Output:
item #0: 20
item #1: 30
item #2: 40
item #3: 50
Just some rapid prototype coding... Perhaps it might direct you into the right way...
KMSale foo; // sample struct on stack, not initialized!
int my_buffer[12]; // not initialized stack buffer!
/* Assign pointer */
foo.itemsPurchased = my_buffer; // point to my_buffer
/* Print the first element via the struct... */
printf("%02x", foo.itemsPurchased[0]);
Here is it possible to assign int array to the int *itemsPurchased pointer? If it is possible how print the values?
Yes we can assign an array to a pointer as array is a constant pointer and reverse is invalid.
But this assignment should be used very carefully as array will be a stack variable and scope of the variable should be taken care before accessing this structure pointer
Also this method can be preferred over the dynamic memory allocation where memory fragmentation is a concern by malloc and free and we can avoid the dynamic allocation overhead.
Following is the code for this and output of print value in the array:
#include <stdio.h>
typedef struct KnightsMartSale {
char firstName[21];
char lastName[21];
int numItemsOnList;
int *itemsPurchased; // array of item numbers
struct KnightsMartSale *next;
} KMSale;
int main() {
KMSale sale;
int iPos = 0;
int Array[] = {1, 2, 3, 4, 5};
sale.numItemsOnList = sizeof(Array) / sizeof(Array[0]);
sale.itemsPurchased = Array;
for (iPos=0; iPos < sale.numItemsOnList; iPos++) {
printf("sale %d: %d\n", iPos, sale.itemsPurchased[iPos]);
}
return 0;
}
output:
sale 0: 1
sale 1: 2
sale 2: 3
sale 3: 4
sale 4: 5

How do I return a struct (from a function) containing an array with the correct elements in that array?

I'm making a program that returns a struct containing an array, but the elements in the array are completely wrong. I keep searching for an answer on this site, Google, and even Bing and nothing. The best I can find are answers like this:
Functions can't return arrays in C.
However, they can return structs. And structs can contain arrays...
from How to make an array return type from C function?
Now, how do I fix this without the use of pointers?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
struct Codes{
int as;
int a[];
};
struct Codes create(int as){
int a[as];
for(int j = 0;j<as;j++)
a[j]=j+1;
struct Codes c;
c.as = as;
c.a[c.as];
for(int i=0; i<as; i++)
c.a[i] = a[i];
for(int i=0; i<as; i+=1)
printf("%d \n", c.a[i]);
return c;
}
int main(int argc, char **argv) {
struct Codes cd;
int as = 4;
cd = create(as);
for(int i=0; i<4; i+=1)
printf("%d \n", cd.a[i]);
}
Actual output:
1
2
3
4
0
0
2
-13120
Expected output:
1
2
3
4
1
2
3
4
structs with flexible value are not meant to be manipulated by value, only by pointer.
You cannot return a struct with a flexible member by value, because C does not know how many items it needs to allocate to the return value, and how many bytes it needs to copy.
Allocate your struct in dynamic memory using malloc of sufficient size, copy your data into it, and return a pointer to the caller:
struct Codes *c = malloc(sizeof(struct Codes)+as*sizeof(int));
c->as = as;
for (int i = 0 ; i != as ; i++) {
c->a[i] = i+1;
}
return c;
Change your function to return a pointer; make sure the caller frees the result.
In your function, struct Codes create(int as), the struct Codes c; is allocated on the stuck, so the memory is no longer valid once the function returns...
...It is true that the core struct is copied in the return value... but the variable array length c.a isn't part of the struct (it's a memory "trailer" or "footer") and isn't copied along with the return value.
Either:
allocate the struct and pass it to a struct Codes create(struct Codes *dest, int as) function; OR
make the struct array fixed in size struct Codes{ int as; int a[4]; };
Good luck.

creating, passing, getting back Array of a Struct and loop throuh it in C

I need to execute a function that returns array of a specified struct with variable length. Then I should loop through the returned array.
example struct :
typedef struct student {
int id;
char *name;
int grade;
} Student;
function prototypes 1 :
Student *students;
students = findStudentByGrade(int grade);
function prototypes 2 :
Student *students;
int retval = findStudentByGrade(&students, int grade);
I am bit confused on above methods. How can correctly define a array of struct? call function ? and loop through it untill end? Can some one help me please.
You can do this in this way. This code is working. I tested in CodeLite.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct student {
int id;
char *name;
} Student;
Student *findStudent(int *asize, const int grade);
int main(void)
{
Student *stds;
int asize = 0;
stds = findStudent(&asize, 5);
int i;
for (i = 0; i < asize; i++) {
printf("ID : %i\n", stds[i].id);
}
return 0;
}
Student *findStudent(int *asize, const int grade)
{
struct student *stds = malloc(sizeof(struct student) * 3);
stds[0].id = 10;
stds[1].id = 20;
stds[2].id = 40;
*asize = 3;
return stds;
}
Get the array of struc as returned statement and pass an int variable with argument list to get the size back and simply loop through using a for loop. Or else you will find problem in looping. It is more easy to get the array size from the function which create the array.
I mean this is quite a basic question, but:
Defining array of your structures would look like:
int size = ...;
Student *students = (Student*) malloc(sizeof(Student) * size);
Then just pass that to the function (both size and the array) and then just loop until i < size.
Ofcourse, don't forget to:
free(students);
at the end.

dynamically expanding array of struct

I am (trying to) write a server-side daemon in c, and it accepts connections from clients. I need a struct that keeps information on each open connection, so I have created an array of my defined struct, and I have it dynamically re-sizing with realloc.
The problem I have is creating the struct within the array. I keep getting this error:
test.c:41: error: conversion to non-scalar type requested
What am I doing wrong?
I spend most of my time in PHP, and am a noob with c. I realize that I am making some simple, beginner mistakes (in other words, feel free to make fun of me). If I am doing something stupid, please let me know. I've put my quality time in with google, but have not figured it out. I have reproduced the issue on smaller scale, as below:
here is my test.h:
typedef struct test_ test;
and here is my test.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"
//define the struct
struct test_ {
int id;
char *ip;
int user;
char *str;
};
//yes, the list needs to be global
test *test_list;
//
// add an item to the global list
//
int add(int id, char *ip, int size)
{
//
// increment size
if(id>size) {
size = id;
//try to expand the list
test *tmp = realloc(test_list,size);
if(tmp) {
//it worked; copy list back
test_list = tmp;
} else {
//out of memory
printf("could now expand list\n");
exit(1);
}
}
//
// HERE IS THE TROUBLE CODE::
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
test_list[id].id = id;
test_list[id].ip = malloc(strlen(ip));
strcpy(test_list[id].ip,ip);
test_list[id].user = 0;
test_list[id].str = NULL;
}
//
// main
//
int main(void)
{
//initialize
int size = 1;
test_list = malloc(size*sizeof(test));
//add 10 dummy items
int i;
for(i=0; i<10; i++) {
size = add(i, "sample-ip-addr", size);
}
//that's it!
return 0;
}
Try changing
test *tmp = realloc(test_list,size);
to
test *tmp = realloc(test_list,size*sizeof(test));
then delete
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
When you allocate for test_list, there's already space for each member of the struct allocated, so you don't need to do it again. You just have to allocate for any pointers within the struct
The return value from 'malloc' is the memory address you've allocated. You can't cast it to a struct. What would that even mean?
You want something like: test_list=realloc(test_list, num_alloc * sizeof(test_));

Resources