I have an object allocated on the heap. The object will be destroyed from the heap, but I need to preserve it, preferably through copying it and saving the pointer to it.
An example
#include <stdio.h>
#include <stdlib.h>
struct Human
{
int age;
char sex;
float height;
float weight;
};
struct Human *human;
void create_human(int age, char sex, float height, float weight)
{
struct Human *A = (struct Human *) malloc(sizeof(struct Human));
A->age = age;
A->sex = sex;
A->height = height;
A->weight = weight;
// copy A and save the pointer to the copy in the global variable
free(A);
}
int main()
{
create_human(22, 'M', 1.90, 100.0);
printf("Age: %d\tSex: %c\tHeight %.2f\tWeight %.2f\n", human->age, human->sex, human->height, human->weight);
}
Here I need to copy the object A points to and make human point to the copy.
human = (struct Human *) malloc(sizeof(struct Human));
memcpy(human, A, sizeof(struct Human));
If there were pointers to other structs inside Human, this would be slightly more complex!
Edit:
More elegant solution suggested by StoryTeller in comments:
human = (struct Human *) malloc(sizeof(struct Human));
*human = *A;
You probably want something like this:
no more obscure copying into a global variable (avoid global variables whenever possible)
no more cast for malloc
free called once we're done with the created human and not before
#include <stdio.h>
#include <stdlib.h>
struct Human
{
int age;
char sex;
float height;
float weight;
};
struct Human *create_human(int age, char sex, float height, float weight)
{
struct Human *A = malloc(sizeof(struct Human)); // no need to cast
A->age = age;
A->sex = sex;
A->height = height;
A->weight = weight;
return A;
}
int main()
{
struct Human *human = create_human(22, 'M', 1.90, 100.0);
printf("Age: %d\tSex: %c\tHeight %.2f\tWeight %.2f\n", human->age, human->sex, human->height, human->weight);
free(human);
}
If you absolutely want to copy your human into a global variable, you can still do it:
...
struct human *globalhuman;
...
int main()
{
globalhuman = create_human(22, 'M', 1.90, 100.0);
printf("Age: %d\tSex: %c\tHeight %.2f\tWeight %.2f\n", globalhuman ->age, globalhuman ->sex, globalhuman ->height, globalhuman ->weight);
free(globalhuman );
}
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
medication createMedication(char name[], float concentration, int quantity, float price)
{
medication m;
strcpy(m.name, name);
m.concentration = concentration;
m.price = price;
m.quantity = quantity;
return m;
}
I get the uninitialized local variable "m" used error for line 10(where the strcpy() function is) and I don't know why.
The header file that it's using is:
#pragma once
typedef struct {
char* name;
float concentration;
int quantity;
float price;
}medication;
medication createMedication(char name[], float concentration, int quantity, float price);
char* getName(medication *m);
float getConcentration(medication *m);
int getQuantity(medication *m);
float getPrice(medication *m);
And the whole file:
#include <stdlib.h>
#include "medication.h"
#include <string.h>
#include <stdio.h>
#pragma warning(disable : 4996)
medication createMedication(char name[], float concentration, int quantity, float price)
{
medication m;
strcpy(m.name, name);
m.concentration = concentration;
m.price = price;
m.quantity = quantity;
return m;
}
char* getName(medication* m)
{
return m->name;
}
float getConcentration(medication* m)
{
return m->concentration;
}
float getPrice(medication* m)
{
return m->price;
}
int getQuantity(medication* m)
{
return m->quantity;
}
void toString(medication m, char str[])
{
sprintf(str, "Medication %s: Concentration:%f , Price:%f ,Quantity:%d", m.name,m.concentration,m.price,m.quantity);
typedef struct {
char* name;
float concentration;
int quantity;
float price;
}medication;
Here you have declared the char pointer vaiable "name" but you you haven't allocated memory for this pointer. So it may be pointing to some garbage value or address. You have to allocate memory before copying any data to this pointer "name". After declaration of "m" variable you have to allocate memory for "name" pointer.
medication m;
m.name = (char *)malloc(size);
name variable inside medication struct is culprit in this case.
in G++ this code works fine. but Visual Studio Compiler does not work.
I have changed char *name to char name[256 {or any size}].
This should work
I am working through the Learn C the Hard Way and I am currently stuck on the extra credit exercise number 16.
I am currently trying to adapt their code and making the struct on the stack instead of the heap but my code is giving me segmentation fault and I am unsure why or how to proceed. Any advice is greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
void Person_create(struct Person p,char *name,int age,int height,int weight)
{
p.name = name;
p.age = age;
p.height = height;
p.weight = weight;
}
void Person_print(struct Person who)
{
printf("Name: %s\n", who.name);
printf("\tAge: %d\n", who.age);
printf("\tHeight: %d\n", who.height);
printf("\tWeight: %d\n", who.weight);
}
int main(int argc, char *argv[])
{
// make two people structures
struct Person joe;
struct Person frank;
Person_create(
joe,"Joe Alex",32,64,140);
Person_create(
frank,"Frank Blank",20,72,180);
// print them out
Person_print(joe);
Person_print(frank);
// make everyone age 20 years and print them again
joe.age += 20;
joe.height -= 2;
joe.weight += 40;
Person_print(joe);
frank.age += 20;
frank.weight += 20;
Person_print(frank);
return 0;
}
The reason your code produces errors at runtime is that C passes structs by value, meaning that the following assignments inside Person_create have no effect:
p.name = name;
p.age = age;
p.height = height;
p.weight = weight;
This makes no changes to joe and frank inside main(), leading to undefined behavior on printing, because name data member of the struct Person remains uninitialized.
In order to fix this problem, pass struct Person by pointer, and apply -> operator in place of . operator:
void Person_create(struct Person *p,char *name,int age,int height,int weight)
{
p->name = name;
p->age = age;
p->height = height;
p->weight = weight;
}
...
Person_create(&joe, "Joe Alex", 32, 64, 140);
// ^ Pass an address
It is asking for me to not use pointers or malloc, and says as advice to look into creating a struct on the stack
Your code already creates the structs on the stack. If you would like to get rid of pointers completely, change Person_create to *return` a new person, like this:
struct Person Person_create(char *name,int age,int height,int weight) {
struct Person p;
p.name = name;
p.age = age;
p.height = height;
p.weight = weight;
return p;
}
...
joe = Person_create("Joe Alex", 32, 64, 140);
Define finction Person_create the following way
void Person_create(struct Person *p, char *name, int age, int height, int weight)
{
p->name = name;
p->age = age;
p->height = height;
p->weight = weight;
}
and call it like
Person_create( &joe, "Joe Alex", 32, 64, 140 );
A more sophisticated approach is the following
#include <string.h>
#include <stdlib.h>
//...
void Person_create(struct Person *p, const char *name, int age, int height, int weight)
{
size_t n = strlen( name );
p->name = malloc( ( n + 1 ) * sizeof( char ) );
strcpy( p->name, name );
p->age = age;
p->height = height;
p->weight = weight;
}
However in this case you should remember to free the allocated memory when the object of the structure leaves its scope.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *name;
int age;
int height;
int weight;
}Person;
void Person_print(Person who)
{
printf("Name: %s\n", who.name);
printf("\tAge: %d\n", who.age);
printf("\tHeight: %d\n", who.height);
printf("\tWeight: %d\n", who.weight);
}
int main(int argc, char *argv[])
{
Person joe= {"Joe Alex", 32, 64, 140};
Person frank={"Joe Alex", 32, 64, 140};
printf("Joe is at memory location: %p\n", &joe);
Person_print(joe);
printf("Frank is at memory location: %p\n", &frank);
Person_print(frank);
joe.age += 20;
joe.height -= 2;
joe.weight += 40;
Person_print(joe);
frank.age += 20;
frank.weight += 20;
Person_print(frank);
return 0;
}
Typedef the struct called 'Person', then you don't have to use 'Person create'.
I have the following code in C:
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE
void *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
How could I find the pointer to the memory point to the first element of struct Student in the memory?
I try to do it in the following way:
int i = 0;
for(i = 0; i < NUM_OF_PEOPLE; i++)
{
Student * student_p = p.student[NUM_OF_PEOPLE];
}
It does not work, so can we allocate memory in the way?
And how to find the first element of struct Student in the memory?
What you have is an ancient way of having a flexible array member, which was technically also undefined behavior.
You are looking for this.
First, you need to define your struct like this (I don't know what the ints before the Students are, so let's just call it id):
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
Student student;
} StudentAndId;
typedef struct
{
int id;
StudentAndId students[];
} People;
Note the lack of size in the array inside People. Now you do this:
People *p = malloc(sizeof(People) + sizeof(StudentAndId[NUM_OF_PEOPLE]));
Then you can access students inside p as if it was an array of NUM_OF_PEOPLE elements.
Remember to compile with C99 (or C11) support. With gcc that would be -std=c99 or -std=gnu99.
This will allocate memory for storing the date but how you access it depends on how you store date. using C pointers you can store and access data using this structure and allocation but accessing the members will not be direct. it will involve pointer arithmetic. So better to use other structure if possible. If using this way of allocation then you need to do pointer arithmetic to get the next elements.
Try this:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE 10
int main()
{
People *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
int* id = (int*)(p+1);
Student* s = (Student*)(id+NUM_OF_PEOPLE);
printf("Size of People : %d\n", sizeof(People));
printf("p points to : %p\n", p);
printf("id points to : %p\n", id);
printf("s points to : %p\n", s);
}
Here's a sample output:
Size of People : 8
p points to : 0x80010460
id points to : 0x80010468
s points to : 0x80010490
You may want to add the id field to your Student data structure, e.g.:
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
Then, you can define a structure having a fixed header (in this case, this can be the number of students), followed by a variable-sized array of Students:
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
This blog post explains this technique of having "arrays of size 1", including a discussion of the alignment problem.
I won't repeat the original blog post code here. Just consider that you can use the portable offsetof() instead of the Windows-specific FIELD_OFFSET() macro.
As a sample code, you may want to consider the following:
#include <stdio.h> /* For printf() */
#include <stddef.h> /* For offsetof() */
#include <stdlib.h> /* For dynamic memory allocation */
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
int main(int argc, char* argv[]) {
People* people;
const int numberOfStudents = 3;
int i;
/* Dynamically allocate memory to store the data structure */
people = malloc(offsetof(People, students[numberOfStudents]));
/* Check memory allocation ... */
/* Fill the data structure */
people->count = numberOfStudents;
for (i = 0; i < numberOfStudents; i++) {
people->students[i].id = i;
people->students[i].age = (i+1)*10;
people->students[i].phoneNumber = 11000 + i;
}
/* Print the data structure content */
for (i = 0; i < people->count; i++) {
printf("id: %d, age=%d, phone=%d\n",
people->students[i].id,
people->students[i].age,
people->students[i].phoneNumber);
}
/* Release the memory allocated by the data structure */
free(people);
return 0;
}
Output:
id: 0, age=10, phone=11000
id: 1, age=20, phone=11001
id: 2, age=30, phone=11002
I understand how to create a struct on the heap using malloc. Was looking for some documentation regarding creating a struct in C on the stack but all docs. seem to talk about struct creation on heap only.
The same way you declare any variable on the stack:
struct my_struct {...};
int main(int argc, char **argv)
{
struct my_struct my_variable; // Declare struct on stack
.
.
.
}
To declare a struct on the stack simply declare it as a normal / non-pointer value
typedef struct {
int field1;
int field2;
} C;
void foo() {
C local;
local.field1 = 42;
}
an answer to 17.4 Extra Credit (in Zed's book "Learn C the Hard Way") using functions
#include <stdio.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
struct Person Person_create(char *name, int age, int height, int weight)
{
struct Person who;
who.name = name;
who.age = age;
who.height = height;
who.weight = weight;
return who;
}
void Person_print(struct Person who)
{
printf("Name: %s\n", who.name);
printf("\tAge: %d\n", who.age);
printf("\tHeight: %d\n", who.height);
printf("\tWeight: %d\n", who.weight);
}
int main(int argc, char *argv[])
{
// make two people structures
struct Person joe = Person_create("Joe Alex", 32, 64, 140);
struct Person frank = Person_create("Frank Blank", 20, 72, 180);
//print them out and where they are in memory
printf("Joe is at memory location %p:\n", &joe);
Person_print(joe);
printf("Frank is at memory location %p:\n", &frank);
Person_print(frank);
// make everyone age 20 and print them again
joe.age += 20;
joe.height -= 2;
joe.weight += 40;
Person_print(joe);
frank.age += 20;
frank.weight += 20;
Person_print(frank);
return 0;
}
I got it to work this way:
#include <stdio.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
int main(int argc, char **argv)
{
struct Person frank;
frank.name = "Frank";
frank.age = 41;
frank.height = 51;
frank.weight = 125;
printf("Hi my name is %s.\n", frank.name);
printf("I am %d yeads old.\n", frank.age);
printf("I am %d inches tall.\n", frank.height);
printf("And I weigh %d lbs.\n", frank.weight);
printf("\n-----\n");
struct Person joe;
joe.name = "Joe";
joe.age = 50;
joe.height = 93;
joe.weight = 200;
printf("Hi my name is %s.\n", joe.name);
printf("I am %d years old.\n", joe.age);
printf("I am %d inches tall.\n", joe.height);
printf("And I weigh %d lbs.\n", joe.weight);
return 0;
}