How to use strings with structs in C? - c

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

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

populating struct fields in a separate function in C

getting empty values in the struct for this implementation since pointers are freed after call to myFunc ends. what's a good way of populating a struct when its fields are populated in a different function?
struct Poke {
char *name;
char *type;
};
void myFunc(struct Poke *p) {
char fish[5] = "fish";
char *name = fish;
char fillet[8] = "fillet";
char *type = fillet;
p->name = name;
p->type = type;
}
int main () {
struct Poke p;
myFunc(&p);
printf("%s\n", (&p)->name);
printf("%s\n", (&p)->type);
}
So you realize that the memory allocated for fish and fillet is deallocated when the function returns.
So you need memory that persists after the function call.
So you go and do some research and discover C's memory allocation functions like malloc and free. You will also need C's string handling functions like strcpy.
Go read about all the functions you can find in the include headers "stdlib.h" and "string.h".
One way is by allocating memory for the strings inside the structure itself, like this:
#include <stdio.h>
#include <string.h>
struct Poke
{
char name[64];
char type[64];
};
void myFunc(struct Poke *p)
{
char fish[5] = "fish";
char fillet[8] = "fillet";
strncpy(p->name, fish, 64);
strncpy(p->type, fillet, 64);
}
int main ()
{
struct Poke p;
myFunc(&p);
printf("%s\n", p.name);
printf("%s\n", p.type);
return 0;
}
You either need to make the strings static (static const for completeness) so they are persistent:
void myFunc(struct Poke *p)
{
static const char fish[5] = "fish";
char *name = fish;
static const char fillet[8] = "fillet";
char *type = fillet;
p->name = name;
p->type = type;
}
Or you need to define your structure members as char arrays and copy the string in:
struct Poke
{
char name[5];
char type[8];
};
void myFunc(struct Poke *p)
{
strcpy(p->name, "fish");
strcpy(p->type, "fillet");
}
The issue in this particular case is that char fish[5] = "fish"; creates a local variable and copies the string "fish" into it. So assigning char *name = fish; then p->name = name; stores the address of this local variable in your struct (and the same goes for p->type).
You can avoid this by directly storing the addresses of the string literals:
char *name = "fish";
char *type = "fillet";
And on a somewhat unrelated note, you don't need to dereference the address of p here:
printf("%s\n", (&p)->name);
printf("%s\n", (&p)->type);
The following is sufficient:
printf("%s\n", p.name);
printf("%s\n", p.type);

Freeing structure elements in C

I have a structure:
struct student{
int roll_no;
char *name = malloc(25 * sizeof(char));;
char *phone_no = malloc(10 * sizeof(char));;
char *dob = malloc(10 * sizeof(char));;
}*s1;
int main(){
s1 = malloc(5 * sizeof(student)); //array of student
//.....
}
What is appropriate code for the complete loop for allocating an array of student of size 'n' and then de-allocating it afterwards?
Note: The question here deals with allocation and de-allocation of elements of the instance of a structure.
This...
typedef struct student{
int roll_no; // (the following illegal syntax commented out)
char *name; // = malloc(25 * sizeof(char));;
char *phone_no; // = malloc(10 * sizeof(char));;
char *dob; // = malloc(10 * sizeof(char));;
}*s1;
...from what is being described as the need, (minus the illegal assignment statements) could probably better be formed as:
typedef struct {
int roll_no;
char *name; //needs memory
char *phone; //needs memory
char *dob; //needs memory
}STUDENT;
Then, use the new variable type: STUDENT, to create the instances of the struct as needed. Your OP indicates you need 5:
STUDENT s[5]; //Although this array needs no memory, the
//members referenced by it do
//(as indicated above)
Now, all that is necessary is to create memory for the 3 members that require it, in each of the 5 instances.
for(i=0;i<5;i++)
{
s[i].name = calloc(80, 1); //calloc creates AND initializes memory.
s[i].phone = calloc(20, 1); //therefore safer than malloc IMO.
s[i].dob = calloc(20, 1); //Also, change values as needed to support actual
//length needs for name, phone and dob
}
// Use the string members of s[i] as you would any other string, But do not
// forget to free them when no longer needed.
...
for(i=0;i<5;i++)
{
free(s[i].name);
free(s[i].phone);
free(s[i].dob);
}
Note, because of the way the array s is created in this example, i.e. with memory on the stack instead of the heap, there is no need to free it.
One other note, the example code above focused on a method to create memory for the char * members of your struct array, but when actually coding for keeps, the return of [m][c][re]alloc should always be checked that memory was created before trying to use the variable. For example:
s[i].name = calloc(80, 1);
if(!s[i].name) //checking that memory was created
{
;//if failed, then handle error.
}
...
In addition to ryyker's answer, if you want to do it dynamically:
#include <stdlib.h>
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main()
{
int i, student_count = 5;
struct student ** s = malloc(sizeof(struct student *) * student_count);
if (s)
{
for (i = 0; i < student_count; ++i)
{
s[i] = malloc(sizeof(struct student));
if (s[i])
{
//set up student's members
}
}
for (i = 0; i < student_count; ++i)
{
//free student's members before the next line.
free(s[i]);
}
free(s);
}
return 0;
}
You must free everything you malloc, and as mentioned in the comments you cannot malloc inside the struct.
#include <stdio.h>
#include <stdlib.h>
#define NUM_STUDENTS 5
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main(void)
{
int i;
// if this was me, I would simply replace this with
// struct student s[NUM_STUDENTS];, but the goal here is to illustrate
// malloc and free
struct student* s = malloc(sizeof(struct student) * NUM_STUDENTS);
if (s == NULL) // handle error
for (i=0; i<NUM_STUDENTS; i++)
{
// sizeof(char) is guaranteed to be 1, so it can be left out
s[i].name = malloc(25);
if (s[i].name == NULL) // handle error
s[i].phone = malloc(10);
if (s[i].phone == NULL) // handle error
s[i].dob = malloc(10);
if (s[i].dob == NULL) // handle error
}
// do stuff with with the data
....
// time to clean up, free in the reverse order from malloc
for (i=0; i<NUM_STUDENTS; i++)
{
// the dob, phone, name order here isn't important, just make sure you
// free each struct member before freeing the struct
free(s[i].dob);
free(s[i].phone);
free(s[i].name);
}
// now that all the members are freed, we can safely free s
free(s);
return 0;
}
User Abhijit gave an answser that was in the right direction, but not complete. His answer should have been:
typedef struct STUDENT{
int roll_no;
char *name;
char *phone;
char *dob;
}student;
void example(int n_students)
{
student **s;
int i;
s= malloc(n_students * sizeof(student *));
for (i=0; i<n_students; i++)
{
s[i]= malloc(sizeof(student));
s[i]->name= malloc(25);
s[i]->phone= malloc(10);
s[i]->dob= malloc(10);
}
// now free it:
for (i=0; i<n_students; i++)
{
free(s[i]->name);
free(s[i]->phone);
free(s[i]->dob);
free(s[i]);
}
free(s);
}

Malloc an array inside a struct

I'm trying to malloc an array inside a struct but I keep getting segmentation errors when I run the program.
The compares function is just something I'm testing so it shouldn't be a part of the problem
typedef struct {
char *string;
} prod_t;
int
main(int agrc, char **argv){
int i = 0;
prod_t *c = NULL;
char str2[100] = "abcd";
c->string = (char *) malloc( 5 * sizeof(char));
strcpy(c->string,str2);
compares(c->stock,str2,i);
return 0;
}
The problem is that you're allocating space for the string, but you're not allocating the struct at all. c remains set to NULL and you're trying to dereference it.
Allocate space for the struct before assigning to its members
prod_t *c = malloc(sizeof(prod_t));
And, as a sidenote for your next-to-fix error: this field doesn't exist
c->stock
You need to allocate space for the struct before you can assign to the string member:
prod_t *c = malloc(sizeof(prod_t));
Also see Do I cast the result of malloc?
First of all, don't cast result of malloc. You only need to do that in C++. In C, it can actually hide potential problems.
Second of all, you need to allocate (or statically declare) your structure.
Third, c->stock doesn't exist. You probably meant c->string.
typedef struct {
char *string;
} prod_t;
int
main(int agrc, char **argv) {
int i = 0;
prod_t *c = malloc( sizeof( prod_t ));
char str2[100] = "abcd";
c->string = malloc( 5 * sizeof(char));
strcpy(c->string,str2);
compares(c->string,str2,i);
return 0;
}

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.

Resources