How can I initialize an array of pointers pointing to a struct? - c

I have the following struct:
struct clientDetails
{
int socket;
char* port;
char* IP;
char* hostName;
int msgSentCount;
int msgRecvCount;
char* status;
char bufferMsg[BUFFER_SIZE];
char blockedUser[4];
int blockedCount;
};
And I have an array of pointers:
struct clientDetails* allClients[4];
How can I initialize all the array elements of allClients to have default values?
I have tried the following but I am getting 'incomplete definition of type struct':
for(int i = 0; i<4; i++) {
allClients[i]->socket = 0;
allClients[i]->port = NULL;
allClients[i]->IP = NULL;
allClients[i]->hostName = NULL;
allCLients[i]->msgSentCount = 0;
allClients[i]->msgRecvCount = 0;
allClients[i]->status = NULL;
allClients[i]->bufferMsg = "";
allClients[i]->blockedUser = {"","","",""};
allClients[i]->blockedCount = 0;
}

For one thing, you need to allocate storage for that struct... right now all you have a single pointer. Right at the top of your loop, you should do something like:
allClients[i] = malloc(sizeof(clientDetails));
It's been a while since I've done structs in "C", but you could/should probably typedef your struct as well.

Related

Memory leak with json_object_get_string

I am quite new in C, and I am using the json-c library. I am completely sure that the problem I have is with json_object_get_string, because if I don't use it and put a string manually in my structure it works in valgrind without any memory leak.
I put a reduced version to make it clearer.
struct Example {
char *id;
char *name;
char *logPath;
};
struct Examples {
struct Example *examples;
size_t size;
};
struct Examples list() {
size_t i, count = 0;
struct Example *examples = NULL;
for (i = 0; i < 59; i++) {
json_object *root_obj = json_object_from_file("path.json");
json_object *jID;
json_object *jName;
json_object *jLogPath;
if (json_object_object_get_ex(root_obj, "Name", &jName) ==
TRUE &&
json_object_object_get_ex(root_obj, "LogPath", &jLogPath) ==
TRUE &&
json_object_object_get_ex(root_obj, "ID", &jID) == TRUE) {
char *id = strdup(json_object_get_string(jID));
char *name = strdup(json_object_get_string(jName));
char *logPath = strdup(json_object_get_string(jLogPath));
json_object_put(root_obj);
count++;
struct Examples *tmpExamples = realloc(examples, count * sizeof(struct Example));
if (tmpExamples == NULL) {
if (examples) {
free(examples);
}
die("Realloc");
}
struct Example example = { id, name, logPath };
examples = tmpExamples;
examples[i] = container;
}
struct Examples examplesList = { examples, count };
return examplesList;
}
I have tried to free the variables that I have assigned with strdup after adding it to the struct, but then I lose the real value of the string. I don't really understand what happens.
In the end I have not complicated with so much char pointer and the chars of the struct I have put it as char array if I can name it that way
struct Example {
char id[64];
char name[30];
char logPath[165];
};
struct Example example;
strcpy(example.id, json_object_get_string(jID));
strcpy(example.name, json_object_get_string(jName));
strcpy(example.logPath, json_object_get_string(jLogPath));
json_object_put(root_obj);

Accessing members of dynamically allocated array of pointers to structs

I need to have a global dynamic array of pointers, in which I will store my structs, beacuse later I will need to iterate through this array to list all the stored information, I also need to be able to read the name, age and job variables from the console, and store them in a person_t in the iterator array.
#include <stdio.h>
#include <stdlib.h>
typedef struct Person
{
char name[30];
int age;
char job[30];
} person_t;
person_t **iterator;
int capacity = 10;
int size = 0;
int main()
{
int i;
*iterator = (person_t *)malloc(capacity * sizeof(person_t));
for (i = 0; i < capacity; ++i)
{
person_t p;
p.age = i;
*iterator[i] = p;
}
return 0;
}
I get no errors/warnings compiling this code (gcc -ansi -pedantic -Wall -Wextra), but when I try to run it, I get a Segmentation fault immediately.
When you do this:
*iterator = (person_t *)malloc(capacity * sizeof(person_t));
You're deferencing iterator, however as a file-scope pointer variable it's initialized to NULL. Attempting to dereference a NULL pointer invokes undefined behavior.
I suspect what you really want is an array of structs, not an array of pointers to structs. That being the case, define iterator as:
person_t *iterator;
Then you allocate memory for it like this:
iterator = malloc(capacity * sizeof(person_t));
Then assign to array elements like this:
iterator[i] = p;
Your stated purpose is to create a "global dynamic array of pointers, in which I will store my structs". The following modification of your code (see comments) will do this:
person_t p[10] = {0};
int main()
{
int i;
// with declaration: person_t **iterator = NULL;,
//following is all that is needed to create an array of pointers:
iterator = malloc(capacity * sizeof(person_t *));//no need to cast return of malloc
for (i = 0; i < capacity; ++i)
{
//person_t p;//moved to scope that will exist outside of main()
p[i].age = i;
iterator[i] = &p[i];//assign the address of the object to the pointer
//iterator[i] is the ith pointer in a collection of
//pointers to be assigned to point to
//instances of struct person_t
}
//Once all fields are populated (to-do), the following will display the results:
for (i = 0; i < capacity; ++i)
{
printf("%d) Name: %s Age: %d Job: %s\n", i, iterator[i]->name,iterator[i]->age,iterator[i]->job);
}
return 0;
}
you are not allocating memory correctly
First you need to allocate memory for a pointer which can store capacity number of address i.e done through iterator = malloc(capacity * sizeof(person_t*)); and then you need to allocate memory for holding each structure element i.e iterator[i] = malloc(sizeof(person_t));
all the malloc'ed memory should be free'd once we are done with it.
Also, have not done the error check for malloc's , that is left as an exercise for you.
int main()
{
int i;
// test data
char *names[] = {"ABC", "DEF"};
char *jobs[] = {"Accountant", "Security"};
int ages[] = {50, 60};
// first allocate memory for iterator , which can hold pointers to store iterator poniters
iterator = malloc(capacity * sizeof(person_t*));
for (i = 0; i < capacity; ++i)
{
// now allocate memory for individual iterator
iterator[i] = malloc(sizeof(person_t));
strcpy(iterator[i]->name,names[i]);
iterator[i]->age = ages[i];
strcpy(iterator[i]->job, jobs[i]);
}
for (i = 0; i < capacity; ++i)
{
printf("name = %s ", iterator[i]->name);
printf("Age = %d ", iterator[i]->age);
printf("Job = %s\n", iterator[i]->job);
}
return 0;
}

Passing a element of a char array into another position

So i have a struct with the following elements:
typedef struct loja{
int numero;
char nome[MAX];
float area;
float faturacao[12];
} Loja[N];
i declared an array vetC[ ] for the struct and my next step was to eliminate a posicion of that array
int EliminarComum(int c,Loja vetC[]){
int posicao, i,a;
posicao = MostrarComum(c,vetC); ///only for the user to choose the position he wishes to eliminate.
if (posicao > c)
printf("can't delete.\n");
else {
for (i = posicao - 1; i < c - 1; i++){
vetC[i]->numero = vetC[i+1]->numero;
vetC[i]->nome = vetC[i+1]->nome;
vetC[i]->area = vetC[i+1]->area;
for(a=0;a<12;a++)
vetC[i]->faturacao[a] = vetC[i+1]->faturacao[a];
c--;
}
}
return c;
}
and in the line of vetC[i]->nome = vetC[i+1]->nome; gives me the error
error: assignment to expression with array type
You cannot assign arrays, but you could assign complete struct loja-objects:
vetC[i] = vetC[i+1];
Conver, for example, the following simple program, which illustrates how an assignment of struct-objects works, while an assignment of a char-array fails:
struct testStruct {
int x;
char str[10];
};
int main() {
struct testStruct t1 = { 10, "Hello" };
struct testStruct t2;
t2 = t1; // legal.
char str1[10] = "Hello";
char str2[10];
// str2 = str1; // illegal; arrays cannot be assigned.
strcpy(str2,str1); // legal (as long as str1 is a valid string)
}

Accessing information from nested struct passed to function

I have the following code:
struct wordPair {
char* englishWord;
char* foreignWord;
};
struct dictionary {
struct wordPair ** data;
int nbwords;
int size;
};
Say I have struct dictionary *dictionaryPtr filled with some data, and I pass it to the following function:
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word)
Within the function dictionary_translate, how can I access the data from the struct wordPair that is nested within the passed struct? I need the function to return a strdup of either englishWord or foreignWord.
I was trying d->data->englishWord, but this gives me the error "request for member 'englishWord' in something not a structure or union".
UPDATE!
What I need the function dictionary_translate to do is determine if there is a matching word pair that contains one of the words passed to it, and return the strdup of the translation (the other word in the pair). Here is the array of words I have defined:
const char* test_translations[NB_TESTS][NB_COLS] =
{
{"hello", "hola"},
{"cat", "gato"},
{"dog", "perro"},
{"thanks", "gracias"},
{"pants", "pantalones"},
{"shoes", "zapatos"},
};
This is how I'm calling the function in the first test I'm trying, which is when the translate function is passed an English word and is required to return a foreign word:
char* translationPtr = NULL;
for (i = 0; i < NB_TESTS; i++) {
translationPtr = dictionary_translate(dictionaryPtr, test_translations[i][0], NULL);
printf("English Word %s translated: %s\n", test_translations[i][0], translationPtr);
}
Here is the translate function as I have it so far...
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word){
int i;
if (d == NULL) return NULL;
for (i = 0; i < d->nbwords; i++) {
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return NULL;
}
As soon as the program gets to the translation function, it crashes. I can't make sense of the debugger to find out what is going on, but it seems like translationPtr never has a value other than NULL (0x0). I'm new with the debugger, so I'm sure it could tell me more if I knew how to read it.
It isn't entirely clear what your function is to do, but about the simplest implementation that might legitimately work is:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair **data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
I think you should review the design of your struct dictionary. Using a double pointer seems unnecessary (or the reason for using it is not obvious). The only advantage is that you'd have a contiguous array of pointers to struct wordPair, while the actual struct wordPair elements need not be contiguously allocated themselves. The following code is a more orthodox definition, assuming that a contiguous array of struct wordPair is not a problem:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair *data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i].englishWord) == 0)
return strdup(d->data[i].foreignWord);
else if (strcmp(foreign_word, d->data[i].foreignWord) == 0)
return strdup(d->data[i].englishWord);
}
return 0;
}
Given the sample test code where one of the arguments to dictionary_translate() is a NULL pointer, the code in the function must be revised not to dereference the argument if it is null. This assumes the double-pointer version of struct dictionary.
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (englishWord != NULL && strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (foreignWord != NULL && strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
d->(*data)->englishWord
Should compile.

lookup table in c

I'm creating a lookup table in C
When I define this:
typedef struct {
char* action;
char* message;
} lookuptab;
lookuptab tab[] = {
{"aa","bb"},
{"cc","dd"}
};
it compiles without errors but when I do something like this:
typedef struct {
char* action;
char* message[];
} lookuptab;
lookuptab tab[] = {
{"aaa", {"bbbb", "ccc"}},
{"cc", {"dd", "eeeee"}}
};
I get the following error:
error: initialization of flexible
array member in a nested context
error: (near initialization for
‘tab[0].message’)
How can I initialize the tab array in the second example?
Note: I know all the values inside the tab array.
UPDATE: message could be of different size, e.g
typedef struct {
char* action;
char* message[];
} lookuptab;
lookuptab tab[] = {
{"aaa", {"bbbb", "ccc", "dd"}},
{"cc", {"dd", "eeeee"}}
};
Thank you very much.
Best regards,
Victor
You can't use structures containing a flexible array member in an array (of the structure). See C99 standard §6.7.2.1/2:
A structure or union shall not contain a member with incomplete or function type (hence,
a structure shall not contain an instance of itself, but may contain a pointer to an instance
of itself), except that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union containing, possibly
recursively, a member that is such a structure) shall not be a member of a structure or an
element of an array.
So, use a char ** instead (and worry about how you know how many entries there are):
typedef struct
{
const char *action;
const char * const *message;
} lookuptab;
static const lookuptab tab[] =
{
{ "aaa", (const char * const []){ "bbbb", "ccc" } },
{ "cc", (const char * const []){ "dd", "eeeee" } }
};
This uses a C99 construct (§6.5.2.5 Compound literals) - beware if you are not using a C99 compiler.
I think you have to specify the array size to use the struct in another array:
typedef struct {
char* action;
char* message[2];
} lookuptab;
You need to specify a size for the message array member in the struct definition:
#define N ... // maximum number of elements in message array
typedef struct
{
char *action;
char *message[N];
} lookuptab;
lookuptab tab[] = {
{"aa", {"bb", "cc"}},
{"dd", {"ee", "ff"}},
...
};
In this case, N must be at least 2.
If you want each instance of the lookuptab struct to have a different number of elements in the message array, then you will have to allocate each message array separately, meaning you won't be able to use a static initializer:
typedef struct
{
char *action;
char **messages;
} lookuptab;
lookuptab *newEntry(const char *action, size_t numMessages, ...)
{
lookuptab *entry = malloc(sizeof *entry);
if (entry)
{
entry->action = malloc(strlen(action) + 1);
if (entry->action)
strcpy(entry->action, action);
if (numMessages > 0)
{
entry->messages = malloc(sizeof *entry->messages * numMessages);
if (entry->messages)
{
size_t i;
va_list ap;
va_start(ap, numMessages);
for (i = 0; i < numMessages; i++)
{
char *nextMessage = va_arg(ap, char *);
entry->messages[i] = malloc(strlen(nextMessage) + 1);
if (entry->messages[i])
strcpy(entry->messages[i], nextMessage);
}
}
}
}
return entry;
}
int main(void)
{
lookuptab *tab[ENTRIES]; // for some number of ENTRIES
tab[0] = newEntry("AA", 2, "BB", "CC");
tab[1] = newEntry("DD", 3, "EE", "FF", "GG");
tab[2] = newEntry("HH", 0);
...
}
Instead of passing the number of messages explicitly, you can use a sentinel:
tab[0] = newEntry("AA", "BB", "CC", NULL);
but you'll either have to cycle through all the arguments twice (first to get the number to allocate the messages array, then to copy each message) or you'll have to realloc() your array for each message, such as:
size_t numMessages = 0;
...
char *nextMessage
while ((nextMessage = va_arg(ap, char *)) != NULL)
{
char **tmp = realloc(entry->messages, sizeof *entry->messages, numMessages+1);
if (tmp)
{
entry->messages = tmp;
entry->messages[numMessages] = malloc(strlen(nextMessage) + 1);
strcpy(entry->messages[numMessages], nextMessage);
numMessages++;
}
}
typedef struct {
char* action;
char* message[];
} lookuptab;
lookuptab is an incomplete type. You cannot create objects of that type. Either provide a definite size for the message array
typedef struct {
char* action;
char* message[42];
} lookuptab_definite_size;
or use pointers all around and manage memory "by hand"
typedef struct {
char* action;
char** message;
} lookuptab_pointers_all_around;
you can use the flexible array member (all elements will have the same size), but it's a lot of work :-)
#include <stdlib.h>
typedef struct {
char* action;
char* message[];
} lookuptab;
int main(void) {
lookuptab *tab;
tab = malloc(sizeof *tab + 42 * sizeof *tab->message);
/* tab = malloc(elems * (sizeof *tab + 42 * sizeof *tab->message)); */
/* tab[0] ... tab[elems-1] all have the same size */
if (tab) {
tab->action = NULL;
tab->message[0] = NULL;
tab->message[1] = NULL;
/* ... */
tab->message[41] = NULL;
free(tab);
}
return 0;
}

Resources