dynamically expanding array of struct - c

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_));

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

What am I doing wrong in passing a struct around in C?

So I am working on a project in C that requires that I pass pointers to a struct into functions. The project is structured as follows:
struct structName {
unsigned short thing2;
char thing1[];
};
void function_1(struct structName *s) {
strcpy(s->thing1, "Hello");
printf("Function 1\n%s\n\n", s->thing1); // prints correctly
}
void function_2(struct structName *s) {
// can read thing2's value correctly
// thing1 comes out as a series of arbitrary characters
// I'm guessing it's an address being cast to a string or something?
printf("Function 2\n%s\n\n", s->thing1); // prints arbitrary characters ('É·/¨')
}
int main() {
struct structName s;
function_1(&s);
printf("Main\n%s\n\n", s.thing1);
function_2(&s);
printf("Main 2\n%s\n\n", s.thing1);
}
This code outputs the following:
Function 1
Hello
Main
Hello
Function 2
É·/¨
Main 2
É·/¨
Obviously, the program has more than just what I've written here; this is just a simplified version; so if there's anything I should check that might be causing this let me know. In all honesty I reckon it's probably just a stupid rookie error I'm making somewhere.
[EDIT: Seems like s.thing1 is being mutated in some way in the call to function_2(), since the odd value is replicated in main() - I should point out that in my program the printf()s are located right before the function call and in the first line of the function, so there's no chance that it's being written to by anything I'm doing. I've updated the example code above to show this.]
Thanks in advance!
The structure contains a flexible member at its end, if you declare a static object with this type, the length of this member will be zero, so strcpy(s->thing1, "Hello"); will have undefined behavior.
You are supposed to allocate instances of this type of structure with enough extra space to handle whatever data you wish to store into the flexible array.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct pstring {
size_t length;
char data[];
} pstring;
pstring *allocate_pstring(const char *s) {
size_t length = strlen(s);
pstring *p = malloc(sizeof(*p) + length + 1);
if (p != NULL) {
p->length = length;
strcpy(p->data, s);
}
return p;
}
void free_pstring(pstring *p) {
free(p);
}
int main() {
pstring *p = allocate_pstring("Hello");
printf("Main\n%.*s\n\n", (int)p->length, p->data);
free_pstring(p);
return 0;
}

How to initialize a struct into a pointed struct

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;
}

Add data dynamically to array of pointers to structures within function

I tried many combinations but really nothing worked. It's been long enough so I decided to write this issue.
I just want an array of pointers to structures so I could later easiely sort it by swaping the addresses. I have a function to get data from file and write to array. Unfortunately, it's impossible for me to read this data outside the function.
My last attempt (I deleted file operations as those are not the issue):
Header.h:
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int32_t year;
uint16_t month;
uint16_t day;
} Date;
typedef struct {
char name[16];
Date date;
uint32_t number;
} Player;
size_t readData(Player** players);
Source.c:
#include "Header.h"
size_t readData(Player** players) {
players = NULL;
players = realloc(players, sizeof(Player*) * 1);
players[0] = malloc(sizeof(Player));
strcpy(players[0]->name, "asd");
printf("$ %s\n", players[0]->name);//OK
return 1;
}
int main() {
Player **players = NULL;
uint32_t elemCount, i;
elemCount = readData(players);
printf("> %s", players[0]->name);//BUM - ERROR!
return 0;
}
I'm using Visual Studio Community 2015. I know it's not so much for coding in C but I managed to configure the solution and it doesn't seem to be the thing imo.
I will be very thankful for help. Yet, I'd like to see it as a remake of my code. I tried some other answers to questions on StackOverFlow like this but they didn't help.
If a parameter of a function is not only read and should be an output too, you have to pass a pointer to your data to the function. If your data type is Player** your paramter type has to be Player ***, so the list of players itselfe is able to be changed inside the function.
size_t readData(char* fname, Player*** players) {
// ^ players is a input and output parameter
Player **tempPlayers = *players; // local list of players
tempPlayers = realloc(tempPlayers, sizeof(Player*) * 1);
tempPlayers[0] = malloc(sizeof(Player));
strcpy(tempPlayers[0]->name, "asd");
printf("$ %s\n", tempPlayers[0]->name);//OK
*players = tempPlayers; // write back list of players to paramter
return 1;
}
int main() {
Player **players = NULL;
uint32_t elemCount, i;
char *fileName = NULL;
elemCount = readData(&players);
// ^
printf("> %s", players[0]->name);//BUM - ERROR!
return 0;
}
If you don't want to use *** you can do it like this:
Player* *readData(char* fname, Player** players, size_t *size) {
players = realloc(players, sizeof(Player*) * 1);
players[0] = malloc(sizeof(Player));
strcpy(players[0]->name, "asd");
printf("$ %s\n", players[0]->name);//OK
*size = 1;
return players;
}
players = readData( fileName, players, &elemCount );
You're passing the pointer to the function by value; the original players in main is not changed. This is no different from doing:
#include <stdio.h>
void func(int x)
{
x = 4;
}
int main()
{
int x = 0;
func(x);
printf("%d\n", x); // zero
}
I'm assuming it's the pointers that got you confused, so you should see your mistake now.
To make the modification visible outside of readData, you will need to use three levels of indirection:
size_t readData(Player*** players) {
*players = malloc(sizeof(Player*) * 1);
*(players)[0] = malloc(sizeof(Player));
strcpy((*players)[0]->name, "asd");
printf("$ %s\n", (*players)[0]->name);//OK
return 1;
}
int main() {
Player **players = NULL;
uint32_t elemCount, i;
elemCount = readData(&players);
printf("> %s", players[0]->name); // prints 'asd'
return 0;
}
There is no point using realloc when you know the pointer being passed is always NULL, so I've changed it to malloc instead.
And on a side note: Visual Studio is perfectly suited to C development, and implements parts of C99 and even C11 (historically MSVC was always stuck at C89). You can just use the .c extension for your source files, and this will make the compiler assume the code is C, or you can explicitly set this in the property pages.
parameter passed to readData() must be the address of the caller's pointer 'players'
each of the references in readData() to players must take that into account.
Othewise the caller's pointer 'player' will not be updated.
Then the main() function, call to printf() is trying to output from address 0, resulting in undefiined behaviour, leading to a seg fault event.
in the main() function, if you insert:
printf( "player value; %p\n", (void*)players);
before the current call to printf() you will see the players pointer still contains NULL.

How to store adjacency matrix of a graph using bitmap 2D array

I want to store a adjacency matrix of a very large graph (approx. 40k nodes). But using int and char array for that I am getting segmentation fault due to memory limits.Dynamic allocation using malloc also failed here. Can anyone suggest a method to implement this using a bitmap 2D array?
Here's my implementation so far in C :
#include <stdio.h>
#include <stdlib.h>
int MAX = 50000;
void clustering(char adj[][MAX]);
int count_neighbour_edges(int temp[], int len, char adj[][MAX]);
int main()
{
int nol = 0, i, j, k;
FILE *ptr_file1,*ptr_file2;
struct community
{
int node;
int clust;
};
struct community d;
ptr_file1 = fopen("community.txt","r");
if (!ptr_file1)
return 1;
while(fscanf(ptr_file1,"%d %d",&d.node, &d.clust)!=EOF) //Getting total no. of nodes from here
{
nol++;
}
char adj[nol+1][nol+1]; //Getting segmentation fault here
struct adjacency
{
int node1;
int node2;
};
struct adjacency a;
ptr_file2 = fopen("Email-Enron.txt","r");
if (!ptr_file2)
return 1;
while(fscanf(ptr_file2,"%d %d",&a.node1, &a.node2)!=EOF)
{
adj[a.node1][a.node2] = '1';
adj[a.node2][a.node1] = '1';
}
clustering(adj);
return (0);
}
You can try to put the array in the DATA segment. You do this by declaring it outside any function and later use that memory area as a dynamically sized 2-dimensional array:
char buffer[MY_MAX_SIZE];
int main()
{
...
if ((nol+1)*(nol+1) > MY_MAX_SIZE) {
exit(1); // Too large to fit in buffer!
}
char (*adj)[nol+1] = buffer; // Use the space in buffer as a dynamic 2-dimensional array.
The slightly unintuitive declaration is because the size of nol is unknown at compile time, so I cannot declare buffer as a two-dimensional array of the size you want.
You need to decide on a value for MY_MAX_SIZE that fits the problem size and that your platform can handle, for example
#define MY_MAX_SIZE (40000L * 40000L)

Resources