populating struct fields in a separate function in C - 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);

Related

I am making a code where we create humans, make them family and print their information but I can't print it

Basically, I made a structure which includes informations of a person. When I create them, I then hop into my other function which should print their information but I am stuck at that point.
This is my main where I call my functions:
int main()
{
Person* p1 = person_constructor("Steven", 1970, "male");
display_person(p1);
return 0;
}
This is where I construct my human, I am required to use dynamic memory allocation:
Person* person_constructor(char *name, int year_of_birth, char *sex)
{
Person p = {};
Person* pptr = &p;
strcpy(p.name, name);
p.year_of_birth = year_of_birth;
strcpy(p.sex, sex);
pptr = malloc(strlen(p.name) * sizeof(char) + strlen(p.sex) * sizeof(char) + sizeof(int));
return pptr;
}
And this is the print function which can't print out the name:
void display_person(Person* p)
{
printf("%s",p->name);
}
Your person_constructor() is seriously confused. You set pptr to point to p, only to overwrite it with the pointer to an uninitialised dynamic memory block (with incorrectly determined size).
// Allocate the structure memory
Person* pptr = malloc( sizeof(Person) ) ;
// Assign the structure members
strcpy( pptr->name, name ) ;
pptr->year_of_birth = year_of_birth;
strcpy( pptr->sex, sex ) ;
// Return a pointer to the allocation
return pptr ;
Your constructor should allocate memory for the person object, then initialize the allocated memory, in that order:
Person* person_constructor(char *name, int year_of_birth, char *sex)
{
Person *p = malloc(sizeof(*p));
if (p) {
snprintf(p->name, sizeof(p->name), "%s", name);
p->year_of_birth = year_of_birth;
snprintf(p->sex, sizeof(p->sex), "%s", name);
}
return p;
}
The code that calls the constructor must also free the memory after using it:
int main(void)
{
Person* p1 = person_constructor("Steven", 1970, "male");
if (p1) {
display_person(p1);
free(p1);
}
return 0;
}
Remarks:
Allocate according to the size of your object. You don't show the definition of the person struct, but the two string fields seem to be arrays of a fixed size, so that sizeof(struct Person) already includes them.
I've used snprintf instead of strcpy, becuse it ensures a null-terminated string that does not overflow the memory.
Amended #Observer code to make it more safe, removing not needed code
#define some_value1 64
#define some_value2 64
typedef struct
{
char name[some_value1];
char sex[some_value2];
int year_of_birth;
} Person;
char *safe_strncpy(char *dest, const char *src, size_t length)
{
strncpy(dest, src, length -1);
dest[length - 1] = 0;
return dest;
}
Person *person_constructor(const char *name, const int year_of_birth, const char *sex)
{
Person *pptr;
pptr=malloc(sizeof(*pptr));
if(pptr)
{
safe_strncpy(pptr->name,name, sizeof(pptr->name));
safe_strncpy(pptr->sex,sex, sizeof(pptr->sex));
pptr->year_of_birth=year_of_birth;
}
return pptr;
}
Simplify it to:
//ASSUMING PERSON IS LIKE THIS:
typedef struct person
{
char name[some_value1];
char sex[some_value2];
int year_of_birth;
} Person;
Person* person_constructor(char *name, int year_of_birth, char *sex)
{
Person *pptr;
pptr=malloc(sizeof(*pptr));
memset(pptr->name,'\0',sizeof(pptr->name));
memset(pptr->sex,'\0',sizeof(pptr->sex));
strcpy(pptr->name,name);
strcpy(pptr->sex,sex);
pptr->year_of_birth=year_of_birth;
return pptr;
}
Plus don't forget to check if space has been really allocated dynamically or not

Write to double const pointer

I want to implement my own string implementation for education. For that I defined a struct named string as follows:
struct string {
const char *const data;
const int length;
};
I use functions to create these string structs and then I assign them to variables.
In order to override the const int length I use the following trick:
*(int *) &result.length = // a int
Now I also want to write to the const char *const data.
As far as I know the first const makes sure that you cant edit the items at which the pointer points, and the second const is that you can't point the pointer to a different memory location. These are properties of an immutable string. So my question is: How can I assign something to the const char *const data like I did to the const int length?
Edit: result as shown above is an instance of the struct string
Form the struct string at its declaration and initialize it.
Also recommend to store the size and not the length and use size_t.
#include <stdio.h>
#include <stdlib.h>
struct string {
const char * const data;
const size_t size;
};
struct string string_copy(const char *src) {
size_t size = strlen(src) + 1;
char *copy = malloc(size);
if (copy) {
memcpy(copy, src, size);
} else {
size = 0;
}
struct string retval = {copy, size}; // ****
return retval;
// or return a compound literal (C99)
return (struct string){ copy, size};
}
void string_free(struct string s) {
free((void*)s.data);
}
int main(void) {
struct string a = string_copy("Hello");
printf("%zu <%s>\n", a.size, a.data);
string_free(a);
// do not use `a` subsequently
return 0;
}
I do not recommend to initialize with a string literal like struct string retval = {"World", 6}; as that limits the usefulness of struct string.
Using a opaque struct has many advantages #Jonathan Leffler that exceed this approach - mainly to keep other code from messing with the struct string.

Dynamic memory allocation of a structure

I need to write a program in which is structure with two fields: integer and string. Next I need to write a function which dynamically allocates this structure and takes int and string as parameters to pass them down to allocated structure. This function will also return pointer to newly made structure. Second element of this program should be function which takes struct pointer as parameter, then prints all of the fileds on screen and then free memory of struct. This is the best I could come up with.
#include <stdio.h>
#include <stdlib.h>
struct str{
int num;
char text[20];
};
struct str* return_address(int *num, char *text){
struct str* new_struct=malloc(sizeof(struct str));
new_struct->num=num;
new_struct->text[20]=text;
return new_struct;
};
void release(struct str* s_pointer){
printf("%d %s", s_pointer->num, s_pointer->text);
free(s_pointer);
};
int main()
{
struct str* variable=return_address(1234, "sample text");
release(variable);
return 0;
}
Your array is very small, also it's not dynamic at all. If you are allocating using malloc() anyway, why not allocate everything dynamically?
You cannot assign to an array.
The num member, which I suppose is meant to store the length of the "string", is being assigned a pointer, which is not what you apparently want. And also, the behavior is only defined in very special circumstances when you assign a pointer to an integer, the compiler should be warning you unless you turned off warnings.
Perhaps you want this,
struct string {
char *data;
int length;
};
struct string *
allocate_string(int length, const char *const source)
{
struct string *string;
string = malloc(sizeof *string);
if (string == NULL)
return NULL;
string->length = strlen(source);
// Make an internal copy of the original
// input string
string->data = malloc(string->length + 1);
if (string->data == NULL) {
free(string);
return NULL;
}
// Finally copy the data
memcpy(string->data, source, string->length + 1);
return string;
}
void
free_string(struct string *string)
{
if (string == NULL)
return;
free(string->data);
free(string);
}

How to use strings with structs in 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);
}

How to set a struct member of type string

I have a struct which contains a member called char *text. After I've created an object from the struct, then how do I set text to a string?
If your struct is like
struct phenom_struct {
char * text;
};
and you allocate it
struct phenom_struct * ps = malloc (sizeof (phenom_struct));
then after checking the value of ps is not NULL (zero), which means "failure", you can set text to a string like this:
ps->text = "This is a string";
typedef struct myStruct
{
char *text;
}*MyStruct;
int main()
{
int len = 50;
MyStruct s = (MyStruct)malloc(sizeof MyStruct);
s->text = (char*)malloc(len * sizeof char);
strcpy(s->text, "a string whose length is less than len");
}
Your struct member is not really a string, but a pointer. You can set the pointer to another string by
o.text = "Hello World";
But you must be careful, the string must live at least as long as the object. Using malloc as shown in the other answers is a possible way to do that. In many cases, it's more desirable to use a char array in the struct; i.e. instead of
struct foobar {
...
char *text;
}
use
struct foobar {
...
char text[MAXLEN];
}
which obviously requires you to know the maximum length of the string.
Example:
struct Foo {
char* text;
};
Foo f;
f.text = "something";
// or
f.text = strdup("something"); // create a copy
// use the f.text ...
free(f.text); // free the copy

Resources