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;
}
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"};
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;
}
I have problem with quick sort. It should sort books with author's names. Here is the code
#include <stdio.h>
#include <stdlib.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator (const void * a, const void *b)
{
struct book * ia=(struct book*)a;
struct book * ib=(struct book*)b;
return (strcmp(ia->autor,ib->autor));
}
int main(int argc, char ** argv)
{
int c = 2;
int i;
//Pointer to array of struct pointers, malloc for 2 structs
struct book **ptr = (struct book*)malloc(c*sizeof(struct book));
for(i=0;i<c;i++) {
//malloc for every struct
//also, if I'm doing it right?
ptr[i] = (struct book*)malloc(sizeof(struct book));
printf("Title: ");
scanf("%s",ptr[i]->title);
printf("Autor: ");
scanf("%s",ptr[i]->autor);
}
for(i=0;i<c;i++) {
printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
}
qsort(ptr,2, sizeof(struct book), comparator);
printf("QSORT DONe...\n\n");
for(i=0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
}
return 0;
}
So program compiles but it reaches only to printf("TEST"); (TEST prints on screen) and then it crashes.
Did I destroy my array with that quick sort? Or what could happen?
Also could you check my code if it's ok? Especially what mallocs (really) do in my code, because I'm not sure if I used them properly.
Thanks!
There were some small issues and confusions:
1) You were missing #include <string.h> for strcmp
2) You were allocating an array of pointers, which is probably not what you meant to do. An array in C is a pointer to the first element of the array, therefore if you allocate using (struct book*) malloc(n * sizeof(struct book)) you're already allocating a full array of n books.
You could also allocate an array of pointers to books, in which case you'd need to assign each pointer to a newly allocated book.
So you could do either of the following (and your code is mixing both):
struct book** ptr = (struct book**) malloc(c * sizeof(struct book*));
struct book* ptr = (struct book*) malloc(c * sizeof(struct book));
In the first case, you need to allocate new books (and therefore the malloc inside the loop would make sense)
In the second case, you just use the array directly, which is what I changed the following code to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator(const void * a, const void *b)
{
struct book * ia = (struct book*)a;
struct book * ib = (struct book*)b;
return (strcmp(ia->autor, ib->autor));
}
int main(int argc, char ** argv)
{
int c = 3;
int i;
//Pointer to array of struct pointers, malloc for 2 structs
struct book* ptr = (struct book*) malloc(c*sizeof(struct book));
if (ptr == NULL) {
printf("Could not allocate data\n");
return 1;
}
for (i = 0;i<c;i++) {
printf("Title: ");
scanf("%s", ptr[i].title);
printf("Autor: ");
scanf("%s", ptr[i].autor);
}
for (i = 0;i < c;i++) {
printf("Before Quick sort Autor: %s, Title : %s \n", ptr[i].autor, ptr[i].title);
}
qsort(ptr, c, sizeof(struct book), comparator);
printf("QSORT Done...\n\n");
for (i = 0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n", ptr[i].autor, ptr[i].title);
}
free(ptr);
return 0;
}
3) Finally, it is a good practice to test the result of your malloc and to call free when you don't need it anymore.
It is shown for the point to be changed(for Pointer to array of struct pointers(but double pointer is not necessary)) following as
#include <string.h>
struct book * ia=*(struct book**)a;
struct book * ib=*(struct book**)b;
struct book **ptr = malloc(c*sizeof(struct book*));
qsort(ptr,2, sizeof(struct book*), comparator);
Perhaps version what you want
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator (const void * a, const void *b)
{
struct book * ia=(struct book*)a;
struct book * ib=(struct book*)b;
return (strcmp(ia->autor,ib->autor));
}
int main(int argc, char ** argv)
{
int c = 2;
int i;
struct book *ptr = malloc(c*sizeof(struct book));
for(i=0;i<c;i++) {
printf("Title: ");
scanf("%s",ptr[i].title);
printf("Autor: ");
scanf("%s",ptr[i].autor);
}
for(i=0;i<c;i++) {
printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
}
qsort(ptr,2, sizeof(struct book), comparator);
printf("QSORT DONe...\n\n");
for(i=0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
}
return 0;
}
I'm going to give you an answer which will keep the definition of ptr, which is a pointer to a pointer to struct book, and also change a minimal amount of your code. This means we will allocate an array of pointers to struct book, and then for each pointer in that array we will allocate an actual object struct book.
The first malloc will allocate an array of cpointers to struct book:
struct book **ptr = (struct book**)malloc(c*sizeof(struct book*));
The for loop which allocates an object struct book using malloc is then correct.
The second correction is at the qsort() call. We are sorting pointers to struct book, not actual objects struct book.
qsort(ptr,4, sizeof(struct book*), comparator);
Then the comparison function needs a fix. Since we are sorting pointers, the comparison function will return a pointer to a pointer to struct book. So we need to dereference that pointer to our pointer to struct book:
int comparator (const void * a, const void *b)
{
struct book* ia=*(struct book**)a;
struct book* ib=*(struct book**)b;
return (strcmp(ia->autor,ib->autor));
}
What is the best way to search through an array of structs containing both strings and integers in C programming?
An axamle of the array of structs:
struct person {
int age;
int length;
char fname[20];
char lname[20];
};
Typedef struct person Person
int main()
{
Person personarray[100];
}
One commenter pointed out you can use bsearch.
But a simple loop based coding example to answer your question about how to walk the array follows.
#define MAX_NUMBER_OF_PEOPLE 100
#define NAME_BOB "Bob"
struct person {
int age;
int length;
char fname[20];
char lname[20];
};
typedef struct person Person;
int main()
{
Person people[MAX_NUMBER_OF_PEOPLE];
for (int i; i < sizeof (people) / sizeof (struct people); i++) {
Person *person = &people[i];
if (person->age == 21) {
println("%s %s can legally drink\n",
person->fname, person->lname);
}
if (strncmp(person->fname, NAME_BOB, sizeof (NAME_BOB)) == 0) {
println("Bob is %d years old\n",
person->age);
}
}
}