Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to fill a struct with strings.
struct person {
char *name
char age
};
int record_values(struct person *dude, const char *his_name, char his_age)
{
dude->name = malloc(strlen(his_name)*sizeof(char)); //Get space for name
strcpy(dude->name, his_name); //Set name
strcpy(dude->age, his_age); //Set age
}
However this doesn't work. Any help?
dude->name = malloc(strlen(his_name)*sizeof(char)); //Get space for name
strcpy(dude->name, his_name); //Set name
strcpy(dude->age, his_age); //Set age
Your first line doesn't allocate enough space. You need one byte for the string terminator.
Your last line calls strcpy, but his_age is not a string.
int record_values(struct person *dude, const char *his_name, char his_age)
{
dude->name = strdup(his_name); // Duplicate name
dude->age = his_age; // Set age (Simple assignment!)
}
Instead of giving pointers on what you should change in your code here an complete working example that hopefully shows the required differences. The code below first creates an struct person but when the function record_values() is called you'll see that it first has to check if dude-name is not pointing to an char array already. Not having this check would create a memory leak in your code and the previous dude->name will never be freed. Also it allocates one extra char space in the char array for the string terminator (strcpy will copy it as well). This will avoid overflow errors. The function returns nothing, so make it an void functions rather than an function returning an int. The value of dude->age is not a pointer to memory space, therefore strcpy should not be used but dude->age = his-age which copies the values of variables.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person {
char *name;
char age;
};
struct person * record_alloc(const char *his_name, char his_age);
void record_values(struct person *dude, const char *his_name, char his_age);
void record_free(struct person * dude);
struct person * record_alloc(const char *his_name, char his_age){
struct person * dude;
dude = malloc(sizeof(struct person));
if (his_name != NULL){
record_values(dude, his_name, his_age);
} else {
dude->age = 0;
dude->name = NULL;
}
return dude;
}
void record_values(struct person *dude, const char *his_name, char his_age)
{
size_t nameSize;
if (dude->name)
free(dude->name);
nameSize = (strlen(his_name) + 1) * sizeof(char);
dude->name = malloc(nameSize);
strcpy(dude->name, his_name);
dude->age = his_age;
return;
}
void record_free(struct person * dude){
if (dude->name)
free(dude->name);
free(dude);
return;
}
int main(int argc, const char * argv[]) {
struct person * p;
// allocate and set values
p = record_alloc("John Smith", 32);
printf("%s is %i years old\n", p->name, p->age);
// set new values for p
record_values(p, "John Doe", 37);
printf("%s is %i years old\n", p->name, p->age);
// free p
record_free(p);
return 0;
}
You might prefer to use designated initializers:
#include <stdio.h>
#include <string.h>
typedef struct {
char *name;
char age;
} person;
int record_values(person *dude, const char *his_name, char his_age)
{
*dude = (person) {.name = strdup(his_name), .age = his_age};
}
int main()
{
person p;
record_values(&p, "bob", 27);
printf("Hello, I am %s and I am %d years old!\n", p.name, p.age);
return 0;
}
Hello, I am Bob and I am 27 years old!
Since strdup is not a part of c99 your compiler might generate warnings, to get rid of them you need to compile it with -std=gnu99:
gcc -std=gnu99 -o main *.c
Or use your own version of this, which might look like this:
#include <stdlib.h>
char * strdup(const char *in) {
char *out = malloc(sizeof(in) + 1);
int i;
for (i = 0; in[i] != '\0'; ++i)
out[i] = in[i];
return out;
}
Related
In c I am trying to assign a char array inside a struct with a user provided value, here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct person
{
char name[20];
int age;
};
struct person *assign(char arr[], int age)
{
struct person *x = malloc(sizeof(struct person));
x->name[20] = arr[20];
x->age = 21;
return x;
}
int main()
{
char name[20] = "Arthur morgan";
int age = 34;
struct person* person1 = assign(name, age);
printf("name: %s\n", person1->name);
printf("age: %d\n", person1->age);
return 0;
}
The problem is that the name prints nothing for some reason, the age however prints as expected.
Why is the name not printing correctly?
x->name[20] = arr[20];
It does not copy the array
It copies 1 character and you are accessing array outside its bounds which is undefined behaviour (UB)
It is better to use objects not types in sizeof
Always check the result of malloc
You need to copy the string using strcpy function
struct person *assign(char arr[], int age)
{
struct person *x = malloc(sizeof(*x));
if(x)
{
strcpy(x->name,arr);
x->age = 21;
}
return x;
}
https://godbolt.org/z/vKddb4b9a
This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 3 years ago.
I created a linked list that contains a char array. Then I tried to print it using %s and it would not print. I know I have to transform the char by adding in '\0' so that it can print using '/0'. But I'm not sure why.
For example if I input:
Bob 20
It should print:
New student created: Bob is 20 years old.
BUT: it's printing (without "Bob"):
New student created: is 20 years old.
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[50];
int age;
struct student *next;
};
struct student *createStudent(char studentName[], int studentAge);
int main(void) {
struct student *studptr;
int myAge;
char myName[50];
scanf("%s %d", myName, &myAge);
studptr = createStudent(myName, myAge);
printf("New student created: %s is %d years old.\n", studptr->name, studptr->age);
free(studptr);
return 0;
}
struct student *createStudent(char studentName[], int studentAge){
struct student * ptr;
ptr = (struct student *)malloc(sizeof(struct student));
ptr->name[50] = studentName[50];
ptr->age = studentAge;
ptr->next = NULL;
return ptr;
}
NOTE: I understand the code below will work and print the correct name, where I add an additional method to change the char array called copyStr(), but I'm not sure why....
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[50];
int age;
struct student *next;
};
struct student *createStudent(char studentName[], int studentAge);
void copyStr(char *source, char *target);
int main(void) {
struct student *studptr;
int myAge;
char myName[50];
scanf("%s %d", myName, &myAge);
studptr = createStudent(myName, myAge);
printf("New student created: %s is %d years old.\n", studptr->name, studptr->age);
free(studptr);
return 0;
}
struct student *createStudent(char studentName[], int studentAge){
struct student * ptr;
ptr = (struct student *)malloc(sizeof(struct student));
//we need to translate the char into a string
copyStr(studentName, ptr->name);
ptr->name[50] = studentName[50];
ptr->age = studentAge;
ptr->next = NULL;
return ptr;
}
void copyStr(char *source, char *target){
int i = 0;
while(source[i] != '\0')
{
target[i] = source[i];
i++;
}
target[i] = '\0';
}
Arrays do not have the assignment operator.
This statement
ptr->name[50] = studentName[50];
tries to assign the non-existent element with the index 50 of the array pointed to by the pointer studentName to the non-existent element of the array ptr->name.
Instead you should use the standard C function strcpy declared in the header <string.h>.
For example
strcpy( ptr->name, studentName );
Adding to #Vlad's answer, Right way to copy arrays is by iterating over them, thereby, picking each element in char array and copying it to new location. strncpy does exactly that along with buffer overflow checks, which makes it better than strcpy.
Please have a look at strcpy documentation, which says : "ensure size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source"
On a completely different side note, if you're looking for one-liner assignment, you're allowed to do this:
char sample[] = {"randomText"};
char sample2[11] = {"randomText"};
This question already has answers here:
How do malloc() and free() work?
(13 answers)
Closed 3 years ago.
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char name[50];
int year_of_birth;
char sex[7];
char father[50];
char mother[50];
char significant_other[50];
char children[50];
};
struct Person* person_constructor(char *name, int year_of_birth, char *sex);
int main(){
struct Person* p1 = person_constructor("Abbas", 1970, "male");
}
struct Person* person_constructor(char *name, int year_of_birth, char *sex) {
struct Person *p;
printf("%s",*name);
printf("%s",*sex);
printf("%d",&year_of_birth);
// how to initalise these here and return name, age and sex everytime , can you tell me in print function
}
i want to do :
Person* person_constructor(char *name, int year_of_birth, char *sex);
A person with the given arguments and return it.
Also allocate memory.
In example code bellow you can find one of possible solutions to your question.
In C language is not possible to return more then one variable, but you can return pointer to constructed structure object and access structure members using notation stuct_ptr->struct_member.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char name[50];
int year_of_birth;
char sex[7];
char father[50];
char mother[50];
char significant_other[50];
char children[50];
};
struct Person* person_constructor(char *name, int year_of_birth, char *sex);
int main(){
struct Person* p1 = person_constructor("Abbas", 1970, "male");
/* it is not possible to return more variables in C */
/* you can use pointer to access members from constructed structure: */
printf("print from main:\n %s %d %s \n", p1->name, p1->year_of_birth, p1->sex);
if( p1 != NULL) free(p1); /* do not forget do deallocate something taht is allocated */
return 0;
}
struct Person* person_constructor(char *name, int year_of_birth, char *sex) {
struct Person *p = calloc(1, sizeof(struct Person));
if( p == NULL ) return p; /* memory alocation failed! */
strcpy(p->name, name);
p->year_of_birth = year_of_birth;
strcpy(p->sex, sex);
printf("print from constructor:\n");
printf("%s ",p->name);
printf("%s ",p->sex);
printf("%d \n",p->year_of_birth);
return p;
}
Why am I getting a segmentationfault when it tries to print the second member in the list?
After printing the first element of the list, the debugger opens the stdio.h and says:
At C:\TDM-GCC-32\include\stdio.h:255
At C:\TDM-GCC-32\include\stdio.h:256
At C:\TDM-GCC-32\include\stdio.h:258
At C:\TDM-GCC-32\include\stdio.h:259
Here is the code.
#include <stdio.h>
#include <stdlib.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char Name, char Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = Name;
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
Ausgabe(liste);
return 0;
}
The error is in the declaration of the add() function. The strings should be char pointers, not chars.
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse){
The signature of the function add is inconsistent to the declaration and usage to the members of Student. Change the signature as follows.
void add(char* Name, char* Adresse, unsigned long Mtnr, short Kurse)
On the long run, it might also be necessary to create copies of Name and Adresse in add, as the caller of add might deallocate them, perhaps causing undesired behaviour.
While Marc Is correct with his observation, there is one more thing you may want to fix here.
When you add a record, you allocate it, but you do not allocate the content of it's pointers (Specifically = for the name and address pointers). The add function just point them to the input's address. this is a problem because the data in the address supplied to the add function is likely to change if, for example, it's a user input, or some other external buffer.
in the code snipped below I fixed the 'name', but left the address as is. please run it and see what happens. (assaf's record displays david's address)
hope this helps
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = malloc(strlen(Name)+1);
strcpy(add->Name, Name);
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
char name_buf[100];
char address_buf[100];
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
sprintf(name_buf,"assaf stoler");
sprintf(address_buf,"maria 8");
add(name_buf, address_buf, 8888, 8);
sprintf(name_buf,"david david");
sprintf(address_buf,"some street 9");
add(name_buf, address_buf, 9999, 9);
Ausgabe(liste);
return 0;
}
EDIT: Op asked some questions, and the comment space is limited, so I'll add below:
A pointer is just an object pointing somewhere in memory. it's size is fixed. the content it's pointing to will vary.
When you include a pointer to a string in a structure, the space where the string is kept need to be allocated / accounted for. it is not part of the sizeof(struct).
In your original example the pointers were pointing to constant strings (which reside in the static code, usually the data section, allocated by the compiler), which is why your original code was able to access the strings.
In a more realistic case, the input data is not part of the program data, but is received by some input method (which my *buf was to emulate). as such, pointing your name and address at it would break the program, as the pointer you point to may have it's content changed. therefor copying of the data (string / array) is needed, and since we copy the data, we need to allocate space for it, and point our (name/address) pointer at it.
Alternate option is to use non-pointer array for name and address as in:
struct Student {
char Name[20];
char Adresse[60];
unsigned long Mtnr;
...
}
In this scenario, sizeof (struct Student) would actually include all the space for those fields. you still need to use strcpy or memcpy, as well as check for and handle strings that are too long to fit in your pre-defined length.
Hope this helps
I've encountered a problem trying to reduce the size of my code. What I was trying to do was passing either name or color to function writedata so that I wouldn't have to write it twice for each case.
typedef struct Pet{
char* name;
char* color;
} pet;
void writedata(pet *Pet, char string[], const char field[]){
gets(string);
Pet->field= (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
strcpy(Pet->field, string);
}
The call of the function:
writedata(Pet, string, name);
I'm quite sure I got something wrong.
update: the whole code http://ideone.com/Y7L8Hu
update2: I tried to implement it using offset according to BLUEPIXY's advice but it seems I misunderstand manipulations with fields using their addresses... I believe the problem could be that the fields aren't initialized in the first place, but then again, my aim is to initialize them.
typedef struct Pet{
char* name;
int legs;
char* color;
} pet;
void writedata(pet *Pet, size_t FIELD){
char string[50];
gets(string);
(char*)Pet+offsetof(struct Pet, FIELD) = (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
strcpy((char*)Pet+FIELD, string);
}
That's not how C works. However, I think using string comparison can achieve what you need:
if (strcmp(field, "name") == 0)
{
Pet->name = ...
}
else if (strcmp(field, "color") == 0)
{
Pet->color = ...
}
And call it with a string literal:
writedata(Pet, string, "name");
Using enum is also an option.
BTW, don't use gets, it's dangerous, use fgets instead.
use macro function sample.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define writedata(var, buffer, field) \
do {\
int len = strlen(buffer);\
var->field = (char*)malloc(len + 1);\
memcpy(var->field, buffer, len+1);\
}while(0)
typedef struct Pet{
char* name;
int legs;
char* color;
char* voice;
} pet;
void addpet(pet* Pet, int *TotalLegs){//Can not be used reference(&) in C
char buff[50];
int len;
puts("Input name");
scanf("%49[^\n]", buff);
writedata(Pet, buff, name);
puts("How many legs?");
scanf("%d%*c", &Pet->legs);
puts("What does it say?");
scanf("%49[^\n]%*c", buff);
writedata(Pet, buff, voice);
puts("_____\n");
*TotalLegs += Pet->legs;
}
int main(){
int TotalLegs = 0;
pet* Pet1 = (pet*)malloc(sizeof(pet));
addpet(Pet1, &TotalLegs);
pet* Pet2 = (pet*)malloc(sizeof(pet));
addpet(Pet2, &TotalLegs);
pet* Pet3 = (pet*)malloc(sizeof(pet));
addpet(Pet3, &TotalLegs);
//printf("%s\n", Pet1->name);
//printf("%s\n", Pet1->voice);
printf("The animals have %d legs\n", TotalLegs);
free(Pet1);free(Pet2);free(Pet3);
return 0;
}
A lot of things are wonky in your code.
What you wish to do can be achieved but it takes different type of code than you'd want to write.
What you really want to do is simply create a function that fills in a name and a color.
So here is the simplest way to do it:
typedef struct pet {
char *name;
char *color;
} pet_t;
pet_t * new_pet(const char *name, const char *color)
{
pet_t *p;
p = malloc(sizeof(pet_t));
if ( p == NULL )
return NULL;
p->name = strdup(name); /* allocate space and copy string */
p->color = strdup(color); /* allocate spance and copy string */
return p;
}
void delete_pet(pet_t *p)
{
if ( p-> name )
free(p);
if ( p->color)
free(color);
if ( p )
free(p);
}
int main() {
pet_t *p;
p = new_pet("Harry", "brown");
printf("%s is a %s pet\n", p->name, p->color);
delete_pet(p);
return 0;
}