I want to create a structure in which represents a people.
So i started declare a structure People that contains 3 fields: - firstname : a pointer to a string which represents the first name - lastname : a pointer to a string that represents the name and
age : an integer representing the age.
Now i have to write a function which allocates a new People structure and initializes it with copies of the provided parameters.
The problem i have is that the program always crashes. I dont understand well how can i fill the structure without crashing (thats an online compiler by my school).
Can someone explain and correct me please ?
This is how its looks like :
Array.h :
#ifndef _PEOPLE_H_
#define _PEOPLE_H_
typedef struct {
char* firstname;
char* lastname;
int age;
} People;
People* createPeople(char* firstname, char* lastname, int age);
#endif
Array.c :
#include "People.h"
People* createPeople(char* firstname, char* lastname, int age) {
People people1;
people1.firstname = firstname;
people1.lastname = lastname;
people1.age = age;
}
You cannot return a pointer to a local variable as it is out of scope upon return of function. This means you either need to pass in an instance of Person, or as here, use malloc() to dynamically allocate an instance. I also called strdup() on the two strings, in this example it is not required, but the createPeople() function doesn't know when the objects they point to are out of scope. Minor issue, People is plural, but you only create a a Person.
#include <stdlib.h>
#include <string.h>
typedef struct {
char* firstname;
char* lastname;
int age;
} Person;
Person* createPerson(char* firstname, char* lastname, int age) {
Person *p = malloc(sizeof *p);
if(!p) return NULL;
p->firstname = strdup(firstname);
p->lastname= strdup(lastname);
p->age = age;
return p;
}
int main() {
Person *p = createPerson("Clark", "Kent", 42);
free(p->firstname);
free(p->lastname);
free(p);
}
You first have to include stdlib.h to be able to use malloc and free. Then you allocate enough memory to hold the struct People using malloc.
If the memory allocation fails you return NULL.
If the memory allocation goes well, then you assign each member of the struct value and return it.
#include "People.h"
#include <stdlib.h>
People* createPeople(char* firstname, char* lastname, int age) {
People *people1 = malloc(sizeof(*people1));
if (!people1)
return (NULL);
people1->firstname = firstname;
people1->lastname = lastname;
people1->age = age;
return (people1);
}
Related
I'm trying to implement a struct person, and I need to hide some fields or make them constant.
A trick for create private fields.
Header:
#pragma once
#define NAME_MAX_LEN 20
typedef struct _person {
float wage;
int groupid;
} Person;
const char const *getName (Person *p);
int getId (Person *p);
/// OTHER FUNCTIONS
Source
#include "person.h"
struct _person
{
int id;
float wage;
int groupid;
char name[NAME_MAX_LEN];
};
/// FUNCTIONS
GCC says that person.c:7:8: error: redefinition a 'struct _person' struct _person
I can write this in a header, but after it, I can't use fields of a struct.
typedef struct _person Person;
A struct cannot have multiple conflicting definitions. As such, you can't create a struct that hides some of the fields.
What you can do however it declare that the struct exists in the header without defining it. Then the caller is restricted to using only a pointer to the struct and using functions in your implementation to modify it.
For example, you could define your header as follows:
typedef struct _person Person;
Person *init(const char *name, int id, float wage, int groupid);
const char *getName (const Person *p);
int getId (const Person *p);
float getWage (const Person *p);
int getGroupid (const Person *p);
And your implementation would contain:
#include "person.h"
struct _person
{
int id;
float wage;
int groupid;
char name[NAME_MAX_LEN];
};
Person *init(const char *name, int id, float wage, int groupid)
{
Person *p = malloc(sizeof *p);
strcpy(p->name, name);
p->id = id;
p->wage= wage;
p->groupid= groupid;
return p;
}
...
C has no mechanism for hiding individual members of a structure type. However, by operating only in terms of pointers to such a type, and not providing a definition, you can make the whole type opaque. Users would then have to use the functions you provide to manipulate instances in any way. This is a thing that is sometimes done.
To some extent, you may be able to achieve something like what you describe with a hidden context. For example, consider this:
header.h
typedef struct _person {
float wage;
int groupid;
} Person;
implementation.c
struct _person_real {
Person person; // must be first, and is a structure, not a pointer.
int id;
char name[NAME_MAX_LEN];
};
Now you can do this:
Person *create_person(char name[]) {
struct _person_real *pr = malloc(sizeof(*pr));
if (pr) {
pr->person.wage = DEFAULT_WAGE;
pr->person.groupid = DEFAULT_GROUPID;
pr->id = generate_id();
strncpy(pr->name, name, sizeof(pr->name));
pr->name[sizeof(pr->name) - 1] = '\0';
return &pr->person; // <-- NOTE WELL
} else {
return NULL;
}
}
A pointer to the first member of a structure always points also to the whole structure, too, so if the client passes a pointer obtained from that function back to you, you can
struct _person_real *pr = (struct _person_real *) Person_pointer;
and work on the members from the larger context.
Be well aware, however, that such a scheme is risky. Nothing prevents a user from creating a Person without the larger context, and passing a pointer to it to a function that expects the context object to be present. There are other issues.
Overall, C APIs generally either take the opaque structure approach or just carefully document what clients are permitted to do with the data they have access to, or even just document how everything works, so that users can make their own choices. These, especially the latter, are well aligned with overall C approaches and idioms -- C does not hold your hand, or protect you from doing harm. It trusts you to know what you're doing, and to do only what you intend to do.
You can use a mixin style; e.g. write in the header:
struct person {
float wage;
int groupid;
};
struct person *person_new(void);
char const *getName (struct person const *p);
int getId (struct person const *p);
and in the source
struct person_impl {
struct person p;
char name[NAME_MAX_LEN];
int id;
}
struct person *person_new(void)
{
struct person_impl *p;
p = malloc(sizeof *p);
...
return &p->p;
}
chra const *getName(struct person const *p_)
{
struct person_impl *p =
container_of(p_, struct person_impl, p);
return p->name;
}
See e.g. https://en.wikipedia.org/wiki/Offsetof for details of container_of().
Addendum to John Bollinger's answer:
Although, IMHO, opaque pointer types with accessor functions (init/get/set/destroy) are the most secure approach, there's another option that allows users to place objects on the stack.
It's possible to allocate a single "typeless" chunk of memory as part of the struct and use that memory explicitly (bit by bit / byte by byte) instead of using additional types.
i.e.:
// public
typedef struct {
float wage;
int groupid;
/* explanation: 1 for ID and NAME_MAX_LEN + 1 bytes for name... */
unsigned long private__[1 + ((NAME_MAX_LEN + 1 + (sizeof(long) - 1)) / sizeof(long))];
} person_s;
// in .c file (private)
#define PERSON_ID(p) ((p)->private__[0])
#define PERSON_NAME(p) ((char*)((p)->private__ + 1))
This is a very strong indicator that access to the data in the private__ member should be avoided. Developers that don't have access to the implementation file won't even know what's in there.
Having said that, the best approach is an opaque type, as you may have encountered when using the pthread_t API (POSIX).
typedef struct person_s person_s;
person_s * person_new(const char * name, size_t len);
const char * person_name(const person_s * person);
float person_wage_get(const person_s * person);
void person_wage_set(person_s * person, float wage);
// ...
void person_free(person_s * person);
Notes:
avoid typedef with a pointer. It only confuses developers.
It's better to keep pointers explicit, so all developers can know that the type they're using is dynamically allocated.
EDIT: Also, by avoiding "typedefing" a pointer type, the API promises that future / alternative implementations will also use a pointer in it's API, allowing developers to trust and rely on this behavior (see comments).
When using an opaque type, the NAME_MAX_LEN could be avoided, allowing names of arbitrary length (assuming renaming requires a new object). This is an extra incentive to prefer the opaque pointer approach.
avoid placing the _ at the beginning of an identifier when possible (i.e., _name). Names starting with _ are assumed to have a special meaning and some are reserved. The same goes for types ending with _t (reserved by POSIX).
Notice how I use the _s to mark the type as a struct, I don't use _t (which is reserved).
C is more often snake_case (at least historically). The best known APIs and most of the C standard is snake_case (except where things were imported from C++).
Also, being consistent is better. Using CamelCase (or smallCamelCase) in some cases while using snake_case for other things could be confusing when developers try to memorize your API.
What John Bollinger wrote is a neat way of utilising how structs and memory works, but it's also an easy way to get a segfault (imagine allocating an array of Person and then later passing the last element to a 'method' which accesses the id or it's name), or corrupt your data (in an array of Person the next Person is overwriting 'private' variables of the previous Person). You'd have to remember that you must create an array of pointers to Person instead of array of Person (sounds pretty obvious until you decide to optimise something and think that you can allocate and initialise the struct more efficiently than the initialiser function).
Don't get me wrong, it's a great way to solve the problem, but you've got to be careful when using it.
What I'd suggest (though using 4/8 bytes more memory per Person) is to create a struct Person which has a pointer to another struct which is only defined in the .c file and holds the private data. That way it'd be harder to make a mistake somewhere (and if it's a bigger project then trust me - you'll do it sooner or later).
.h file:
#pragma once
#define NAME_MAX_LEN 20
typedef struct _person {
float wage;
int groupid;
_personPriv *const priv;
} Person;
void personInit(Person *p, const char *name);
Person* personNew(const char *name);
const char const *getName (Person *p);
int getId (Person *p);
.c file:
typedef struct {
int id;
char name[NAME_MAX_LEN];
} _personPriv;
const char const *getName (Person *p) {
return p->priv->name;
}
int getId (Person *p) {
return p->priv->id;
}
_personPriv* _personPrivNew(const char *name) {
_personPriv *ret = memcpy(
malloc(sizeof(*ret->priv)),
&(_personPriv) {
.id = generateId();
},
sizeof(*ret->priv)
);
// if(strlen(name) >= NAME_MAX_LEN) {
// raise an error or something?
// return NULL;
// }
strncpy(ret->name, name, strlen(name));
return ret;
}
void personInit(Person *p, const char *name) {
if(p == NULL)
return;
p->priv = memcpy(
malloc(sizeof(*p->priv)),
&(_personPriv) {
.id = generateId();
},
sizeof(*p->priv)
);
ret->priv = _personPrivNew(name);
if(ret->priv == NULL) {
// raise an error or something
}
}
Person* personNew(const char *name) {
Person *ret = malloc(sizeof(*ret));
ret->priv = _personPrivNew(name);
if(ret->priv == NULL) {
free(ret);
return NULL;
}
return ret;
}
Side note: this version can be implemented so that private block is allocated right after/before the 'public' part of the struct to improve locality. Just allocate sizeof(Person) + sizeof(_personPriv) and initialise one part as Person and second one as _personPriv.
The exercise gives a simple program to create databases, and this program turns around the following structure
struct Address {
int id;
int set;
char name[MAX_DATA];
char email[MAX_DATA];
};
I'm asked to modify the code so I can pass as an argument to the program the maximal length of .name and .email. Now, of course, if instead of defining MAX_DATA as a macro I work with it as a global variable, I get the error: variably modified 'name' at file scope.
Then I tried to create different if-loops aiming to pass the MAX_DATA value by redefiningstruct Address, for example:
if(argc > 6) {
int maxdata = atoi(argv[6]);
struct Address {
int id;
int set;
char name[maxdata];
char email[maxdata];
};
DatabaseSet(conn, id, argv[4], argv[5]);
DatabaseWrite(conn);
break;
}
but DatabaseSet and DatabaseWrite (which work on a struct Connection that relates to another struct Database, who finally relates directly to struct Address) ignore the new lengths of name and email.
EDIT: THANKS.
Thank you all for your comments and answers, your really helped me out with the exercise and with my general undestanding of C.
struct Address {
int id;
int set;
char *name;
char *email;
};
Then allocate memory dynamically in name and email based on your MAXDATA input.
Then you do this struct Address p.
And
p.name = malloc(MAXDATA);
if( p.name == NULL ){
fprintf(stderr,"%s\n","Error in memory allocation");
exit(1);
}
and then when you are done working with it
free(p.name);
In case you allocate memory for email you will have to call free() on it the sane way as shown before.
I am looking at the following code (taken from Learn C the Hard Way) and I am confused about the code the function that starts:
struct Person *Person_create(char *name, int age, int height, int weight)
I understand that the "struct Person" is telling C that this function will return that type of structure; I also understand that the function takes a character pointer and 3 integers as arguments. However, what is confusing to me is that the name of the function starts with a "*". I thought that *Person_create is simply the name of the function so I don't understand why it needs the asterisk.
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.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 = malloc(sizeof(struct Person));
assert(who != NULL);
who->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
return who;
}
void Person_destroy(struct Person *who)
{
assert(who != NULL);
free(who->name);
free(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 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);
// destroy them both so we clean up
Person_destroy(joe);
Person_destroy(frank);
return 0;
}
The space doesn't matter with the *
struct Person *Person_create
is the same as
struct Person* Person_create
The function returns a pointer to a struct Person
As an aside comment, I typically keep the * and & with the type, since you are saying the type of "pointer to struct Person". But others like to put a space between the name and the *.
It means that the function doesn't return a struct Person, it returns a pointer to a struct Person.
This signature:
struct Person *Person_create(char *name, int age, int height, int weight)
is telling you that the type of the return value is the pointer to the struct Person. The name of the function does not start with the star.
In contrast, the signature of the function that would return struct Person looks like this:
struct Person Person_create(char *name, int age, int height, int weight)
In general (and very short), in most cases returning the pointer is more economical than returning the whole structure (simply because it takes less space and time to pass a pointer as a return value). This is probably the main reason why the C functions which are supposed to give back the structure usually give back the pointer to it.
As others have mentioned the * is a part of the return type. You need to return a pointer and not the struct itself because the struct will only exist in the functions stack memory. Once the function returns you will no longer have access to it and it will be garbage.
Only primitives and pointers should be returned this way.
If you insist on returning a struct it needs to be allocated to the heap using malloc inside the function. Later on this memory can be reclaimed by using free if you reference it first. The problem with this is it becomes taxing to remember which structs are allocated and which are not. When freeing the structs it would be a really easy way to run into hard to track down segmentation faults.
In general you should return pointers and primitives because anything else can be big and costly. Depending on your cpu architecture a pointer is about the same size as an int which is next to nothing.
If you're working with struct* 's remember to use -> instead of . to get to its properties.
I am a newbie in C..I am trying to make some sense of how dynamic memory allocation works in case of structures and arrays..So like for example I have a code like..
struct Person
{
int id;
char *name;
char *place;
};
struct Database
{
struct Person *data_rows;
};
I want to dynamically allocate memory for both the character arrays name and place..and the array of struct data_rows..take their size as input..So what should ideally be the order of allocations and the proper syntax for the same? Thanks.
Well, "obviously" you need to get "struct Database" filled in first:
struct Database MyDatabase;
MyDatabase.data_rows=malloc(sizeof(MyDatabase.data_rows[0])*NumberOfPeople);
Ignoring the fact that I didn't check the malloc() for failure, this will give you an array of "struct Person", all uninitialized. So, most likely, you'll want to initialize them:
int i;
for (i=0; i<NumberOfPeople; i++)
{
struct Person* MyPerson;
MyPerson=&MyDatabase.data_rows[i];
MyPerson->id=i;
MyPerson->name=malloc(...);
/* Do something to store the name in MyPerson->name */
MyPerson->place=malloc(...);
/* Do something to store the place in MyPerson->name */
}
Now, the problem here is the "..." I put on the malloc. It's easy if you use a fixed size, but then you could have just declared your struct to be something like
struct Person
{
int id;
char name[100];
char place[200];
};
Basically, I just can't tell what the length of the names should be, hence I just typed it as "...".
Also, I just guessed what the "id" might be. Using the array index is actually somewhat pointless :-)
Of course, you don't have to do it all now. You could just set the name and place pointers to NULL and fill them in later, like when you're reading the data from a file, or whatever you're planning to do. Or you could just not initialize it here at all, if you're confident that your code always "knows" which fields are initialized and which ones are not.
I would highly recommend to write a functions person_new and person_free that would take care of structure memory management:
struct Person* person_new(char *name, char* place) {
struct Person* person = malloc(sizeof(struct Person));
person->name = strdup(name);
person->place = strdup(place);
return person;
}
void person_free(struct Person* person) {
free(person->name);
free(person->place);
free(person);
}
The best thing would be to convert your structs to classes, the following works also for structs...
You define a constructor and destructor in Database and in Person as following:
struct Person
{
Person(){
name = new char[256];
place = new char[256];
};
~Person(){
delete name;
delete place;
}
int id;
char *name;
char *place;
};
struct Database
{
Database(int nPersons){
data_rows = new Person[nPersons];
};
~Database(){
delete data_rows;
};
struct Person *data_rows;
};
or you can do this without a constructor and destructor and allocate all the stuff sequentially in your code, which is a very ugly way to do this!
as:
Database myData;
myData.data_rows = new Persons[40];
for(int i=0; i < 40; i++){
myData.data_rows[i].name = new char[256];
myData.data_rows[i].place = new char[256];
}
Note that data_rows[i] is nothing more than -> *(data_rows + i) which shifts the address of the pointer i times and then dereferences it!
I'm having trouble making a database based on a singly-linked list in C,
not because of the linked list concept but rather the string fields in the struct themselves.
This is an assignment in C and as far as I know (I'm a newbie), C doesn't recognize 'string' as a data type.
This is what my struct code looks like:
typedef struct
{
int number;
string name;
string address;
string birthdate;
char gender;
} patient;
typedef struct llist
{
patient num;
struct llist *next;
} list;
I was thinking of making a struct for the strings themselves so that I can use them in the struct, like this:
typedef struct string
{
char *text;
} *string;
Then I will malloc() each one of them when it is required to make new data of the string type (array of char).
typedef struct string
{
char *text;
} *string;
int main()
{
int length = 50;
string s = (string) malloc(sizeof string);
s->text = (char *) malloc(len * sizeof char);
strcpy(s->text, patient.name->text);
}
Can someone help me figure this out?
Thank you.
On strings and memory allocation:
A string in C is just a sequence of chars, so you can use char * or a char array wherever you want to use a string data type:
typedef struct {
int number;
char *name;
char *address;
char *birthdate;
char gender;
} patient;
Then you need to allocate memory for the structure itself, and for each of the strings:
patient *createPatient(int number, char *name,
char *addr, char *bd, char sex) {
// Allocate memory for the pointers themselves and other elements
// in the struct.
patient *p = malloc(sizeof(struct patient));
p->number = number; // Scalars (int, char, etc) can simply be copied
// Must allocate memory for contents of pointers. Here, strdup()
// creates a new copy of name. Another option:
// p->name = malloc(strlen(name)+1);
// strcpy(p->name, name);
p->name = strdup(name);
p->address = strdup(addr);
p->birthdate = strdup(bd);
p->gender = sex;
return p;
}
If you'll only need a few patients, you can avoid the memory management at the expense of allocating more memory than you really need:
typedef struct {
int number;
char name[50]; // Declaring an array will allocate the specified
char address[200]; // amount of memory when the struct is created,
char birthdate[50]; // but pre-determines the max length and may
char gender; // allocate more than you need.
} patient;
On linked lists:
In general, the purpose of a linked list is to prove quick access to an ordered collection of elements. If your llist contains an element called num (which presumably contains the patient number), you need an additional data structure to hold the actual patients themselves, and you'll need to look up the patient number every time.
Instead, if you declare
typedef struct llist
{
patient *p;
struct llist *next;
} list;
then each element contains a direct pointer to a patient structure, and you can access the data like this:
patient *getPatient(list *patients, int num) {
list *l = patients;
while (l != NULL) {
if (l->p->num == num) {
return l->p;
}
l = l->next;
}
return NULL;
}
I think this solution uses less code and is easy to understand even for newbie.
For string field in struct, you can use pointer and reassigning the string to that pointer will be straightforward and simpler.
Define definition of struct:
typedef struct {
int number;
char *name;
char *address;
char *birthdate;
char gender;
} Patient;
Initialize variable with type of that struct:
Patient patient;
patient.number = 12345;
patient.address = "123/123 some road Rd.";
patient.birthdate = "2020/12/12";
patient.gender = 'M';
It is that simple. Hope this answer helps many developers.
While Richard's is what you want if you do want to go with a typedef, I'd suggest that it's probably not a particularly good idea in this instance, as you lose sight of it being a pointer, while not gaining anything.
If you were treating it a a counted string, or something with additional functionality, that might be different, but I'd really recommend that in this instance, you just get familiar with the 'standard' C string implementation being a 'char *'...
You could just use an even simpler typedef:
typedef char *string;
Then, your malloc would look like a usual malloc:
string s = malloc(maxStringLength);
This does not work:
string s = (string)malloc(sizeof string);
string refers to a pointer, you need the size of the structure itself:
string s = malloc(sizeof (*string));
Note the lack of cast as well (conversion from void* (malloc's return type) is implicitly performed).
Also, in your main, you have a globally delcared patient, but that is uninitialized. Try:
patient.number = 3;
patient.name = "John";
patient.address = "Baker street";
patient.birthdate = "4/15/2012";
patient.gender = 'M';
before you read-access any of its members
Also, strcpy is inherently unsafe as it does not have boundary checking (will copy until the first '\0' is encountered, writing past allocated memory if the source is too long). Use strncpy instead, where you can at least specify the maximum number of characters copied -- read the documentation to ensure you pass the correct value, it is easy to make an off-by-one error.