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);
Related
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.
Is there any manual way to initialize the string in struct ? I used to initialize string in struct using strcpy function such as:
typedef struct {
int id;
char name[20];
int age;
} employee;
int main()
{
employee x;
x.age=25;
strcpy(x.name,"sam");
printf("employee age is %d \n",x.age);
printf("employee name is %s",x.name);
return 0;
}
Strictly speaking this
strcpy(x.name,"sam");
is not an initialization.
if to speak about the initialization then you can do it the following way
employee x = { .name = "sam", .age = 25 };
or
employee x = { .name = { "sam" }, .age = 25 };
This is equivalent to the following initialization
employee x = { 0, "sam", 25 };
or
employee x = { 0, { "sam" }, 25 };
Or you even can use a compound literal of the type employee to initialize the object x though that is not efficient.
Otherwise if is not an initialization but an assignment of the data member of the structure then indeed you have to use at least strcpy or strncpy.
max - including trailing zero
char *mystrncpy(char *dest, const char *src, size_t max)
{
char *tmp = dest;
if (max)
{
while (--max && *src)
{
*dest++ = *src++;
}
*dest++ = '\0';
}
return tmp;
}
You can write your own version of strcpy:
void mycopy(char *dest, const char *source, size_t ndest)
{
assert(ndest != 0);
while (--ndest > 0 && (*dest++ = *source++))
;
}
You're not using strcpy anymore. Plus it is safer.
I have two structures:
struct product {
char *title; // Name of the product
char code[8]; // Max. 7 characters of product ID
int stock; // Current stock (number of units)
double price; // Price of a single unit
};
struct product_array {
struct product *arr;
unsigned int count;
};
I am adding products to product_array with function:
void add_product(struct product_array *pa, const char *title, const char *code,
int stock, double price) {
pa->count++;
struct product* nProduct = malloc(sizeof (struct product));
if (!nProduct) free(nProduct);
init_product(nProduct, title, code, stock, price);
pa->arr = realloc(pa->arr, (pa->count) * sizeof (struct product));
if (!pa->arr) free(pa->arr);
pa->arr[pa->count - 1] = *nProduct;
}
void init_product(struct product *pr, const char *title, const char *code,
int stock, double price) {
int titleLen = strlen(title);
int codeLen = strlen(code);
char *aTitle = calloc((1 + titleLen) * sizeof (char), 1);
strncpy(aTitle, title, titleLen);
char* codePtr = strncpy(pr->code, code, codeLen);
if (codeLen <= 7)
*(codePtr + codeLen) = 0;
else
*(codePtr + 7) = 0;
pr->title = aTitle;
pr->stock = stock;
pr->price = price;
}
add_product works like this in main.c
struct product_array pa;
pa.count = 0;
pa.arr = NULL;
struct product p;
init_product(&p, "test", "0000", 1, 0.50);
print_products(&pa);
add_product(&pa, "Product 1", "0000", 0, 10);
add_product(&pa, "Long name, isn't it", "1234567890", 10, 100);
add_product(&pa, "Product 3", "9999999", 0, 20);
print_products(&pa);
remove_all(&pa);
When I am trying to free all allocated memory, I run to problems. Here is remove all function:
int remove_all(struct product_array *pa) {
unsigned int i;
unsigned int until = pa->count;
struct product *prdPtr = pa->arr;
struct product *next;
for (i = 0; i < until; i++) {
next = prdPtr + 1;
free(prdPtr->title);
free(prdPtr); // this raises error
prdPtr = next;
}
if (pa->arr != NULL) {
free(pa->arr);
}
pa->count = 0;
return 1;
}
The for-loop overflows, but I am now trying to figure out the logic of memory freeing in this context.
In remove_all function I want to free all memory of product_array. I am iterating through every (struct)product in array and freeing the memory of title. After freeing memory of title I am trying to free the struct product itself. It works in first iteration, but when I come to second element, the title could be freed but free(prdPtr) raises SIGABRT.
What might I be missing? Why am I able to free the titles of products but not products themselves?
Thank you for help in advance.
The pa->arr is struct product * not struct product **.
So you have allocated memory for pa->arr and you should free it only once. pa->arr[i] is not a pointer, but just a structure.
You shouldn't free it, but you should free any memory allocated to its members like title.
So update your for loop as
...
for (i = 0; i < until; i++) {
next = prdPtr + 1;
free(prdPtr->title); //just free members
prdPtr = next;
}
if (pa->arr != NULL) {
free(pa->arr);
}
...
Edit:
Also note that there is an unnecessary malloc in add_product. Suggested fix:
void add_product(struct product_array *pa, const char *title, const char *code,
int stock, double price) {
struct product *pa_tmp;
pa->count++;
pa_tmp = realloc(pa->arr, (pa->count) * sizeof (struct product));
if (pa_tmp == null) {
/* handle out of memory error */
}
pa->arr = pa_tmp;
init_product(&pa->arr[pa->count - 1], title, code, stock, price);
}
You free the same Memory block twice:
// this makes pdrPtr to an alias of pa->arr
struct product *prdPtr = pa->arr;
for (i = 0; i < until; i++) {
...
free(prdPtr); // free prdPtr a.k.a. pa->arr
...
}
// here you free the same oject again.
free(pa->arr);
Remove the last free(pa->arr);.
I have seen the answer to this question but it is terribly uninformative for newbie's like myself and still can't manage to get it to work. I am trying to declare a member of the struct called "name" that takes a string value and then trying to figure out how to get that value and print it. Every way I have tried produces an error...
typedef struct {
float height;
int weight;
char name[];
} Person;
void calculateBMI(Person x) {
//printf will go here here
}
int main(int argc, const char * argv[]) {
Person Michael;
Michael.height = 62.0;
Michael.weight = 168;
Michael.name[] "Michael";
Person Steve;
Steve.height = 50.4;
Steve.weight = 190;
Steve.name = "Steven";
calculateBMI(Michael);
calculateBMI(Steve);
}
You have to specify the length of the char array, like this:
typedef struct {
float height;
int weight;
char name[30];
} Person;
Then you use strcpy to populate it:
int main(int argc, const char * argv[]) {
Person Michael;
Michael.height = 62.0;
Michael.weight = 168;
strcpy(Michael.name, "Michael");
Person Steve;
Steve.height = 50.4;
Steve.weight = 190;
strcpy(Steve.name, "Steven");
calculateBMI(Michael);
calculateBMI(Steve);
}
This solution will be the cleanest in all the common cases as you are allocating the space into the stack when you declare a new variable of type Person . In most complex scenarios you don't know the size of the char array and maybe you need to keep it as small as possible. In those case you can use a malloc solution.
Remember that everytime you are using malloc youy have to remember to free the allocated space when you are done with the data.
You can to declare the name member as char * and allocate space to copy the string into it
typedef struct {
float height;
int weight;
char *name;
} Person;
size_t length;
const char *name = "Michael";
length = strlen(name);
Michael.name = malloc(1 + length);
if (Michael.name != NULL)
strcpy(Michael.name, name);
and then when you are done using the struct, don't forget to free
free(Michael.name);
or do as HAL9000 suggests, but this solution wont work for longer strings.
You could simplify this process by creating a helper function like
char *dupstr(const char *src)
{
char *dst;
size_t length;
if (src == NULL)
return NULL;
length = strlen(src);
dst = malloc(1 + length);
if (dst == NULL)
return NULL;
strcpy(dst, src);
return dst;
}
and then
typedef struct {
float height;
int weight;
char *name;
} Person;
Michael.name = dupstr("Michael");
but you will also need to call free after finished using the struct.
typedef struct {
float height;
int weight;
char name[];
} Person;
this struct has no size declared for the name this means that when you create the struct you must also create space for the name .
int main(int argc, const char * argv[])
{
Person *Michael=malloc(sizeof(Person)+strlen("Michael")+1);
if(!Michael)return 1;
Michael->height = 62.0;
Michael->weight = 168;
strcpy(Michael->name,"Michael");
calculateBMI(Michael);
free(Michael);
}
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.