I am new to c programming and I am stuck with this one its a typedef struct and what I would like to do is that I want to create an array from the double pointer from this structure
typedef struct
{
char* firstname;
float price;
}Name,*pName,**ppName;
typedef struct
{
ppName Names;
unsigned int numPerson;
}Book;
And my main which always give me segmentation fault dont mind the loop it is looping until the use says to quit.
int main(void)
{
Book D;
setUpCollection(&D);
while(..)
{
scanf(...);
switch(...)
{
case 1:
if(!AddNewPerson(&D))
return 1;
break;
case 2:
....
case 3:
....
default:
printf("Please enter a valid choice");
}
}
return 0;
}
void setUpCollection(Book* data){
Name name;
pName pname;
pname= malloc(MAX_PERSON* sizeof(pName));
pname= &name;
data->Names= &pname;
data->numPerson= 0;
}
BOOL AddNewPerson(Book* data){
char *title = malloc(sizeof(char));
int len;
Name name;
pName pname;
scanf(...);
len = strlen(firstname);
name.firstname = malloc(len * sizeof(char*));
name.firstname = firstname;
pname= malloc(1);
pname= &name;
data->DVDs[data->numPerson++] = pname;
printf("%0.2f", data->Names[(data->numPerson)-1]->price);
return TRUE;
}
My main problem is that I cant print all the added names and also getting segmentation fault.
There are quite a few errors in your program but let me mention a few:
Doesn't this seem odd to you:
pname= malloc(MAX_PERSON* sizeof(pName));
pname= &name;
you are creating a memory leak by first letting pname point to the array of pName then assigning to &name.
What is this:
char *title = malloc(sizeof(char)); // ?
here you allocate too less space
name.firstname = malloc(len * sizeof(char*));
it should be
name.firstname = malloc(len * sizeof(char) + 1);
or more readable:
name.firstname = malloc(len+1);
this makes no sense again:
pname= malloc(1);
pname= &name;
again you created a memory leak by first letting pname point to a heap block of 1 byte then assigning it to a local variable which you include in data - the local variable is freed up once you leave AddNewPerson() so data will point to garbage.
Instead do something like this (I am no fan of having
typedefs for pointers), also try avoiding naming types
the same way you name variables for clarity:
typedef struct
{
char *firstname;
float price;
} Name;
typedef struct
{
Name** names;
unsigned int numPerson;
} Book;
Now allocate the initial size of your array, the whole point
of having it on the heap is that the array can grow if more
records are added than MAX_PERSONS so you need to keep track
of the number of used records in the array as well as the number
of records allocated
int allocated = MAX_PERSONS;
Book D;
D.names = malloc( allocated * sizeof(Name*) );
D.numPerson = 0;
then loop over user input and add records keeping
track of how many records have been read. Since names
is an array of pointers, you need to allocate a Name
struct each time you add an entry
e.g.
D.names[i] = malloc( sizeof(Name) );
D.names[i]->firstname = strdup(userInputName);
D.names[i]->price = userInputPrice;
then at each iteration check if there is allocated memory left
++i;
if ( i == allocated )
{
// if yes you need to get more memory, use realloc for that
// get e.g. 10 more records
Name* tmp = realloc( D.names, (allocated + 10)*sizeof(Name) );
if ( tmp != NULL )
{
D.names = tmp;
allocated += 10;
}
else
{ .. some error msg .. }
}
Related
I'm learning C.
I have a structure, and if I need to set array of structures -> so I allocate memory for this array. But do I need separately allocate memory for fields in this structure?
Like this:
struct Call{
char *country;
int duration;
};
int main(){
struct Call *calls;
int n;
scanf_s("%d", n);
calls = (struct Call *) calloc(n+1 , sizeof(struct Call));
}
You need not to allocate space for data members of objects of the structure type because they belong to the objects.
But it seems you will need to allocate a character array the pointer to which will be stored in the data member country if you want that objects will be owners of the corresponding strings.
For example
struct Call *calls = calloc( 1, sizeof( struct Call ) );
const char *country = "Some country";
calls->country = malloc( strlen( country ) + 1 );
strcpy( calls->country, country );
When you will deallocate memory for objects of the type struct Call you will need at first to free the memory allocated for character arrays pointed to by data members country.
Yes, you must initialize any pointer before you can dereference it. This means allocating memory for it, or assigning it to already-allocated memory. That's a universal rule in C, there's no special cases for pointers in structures. C will not "recursively" allocate memory for you. Among other things, how would it know how much you need? Consider your simplified code below
int main(){
struct Call *calls;
calls = calloc(1 , sizeof(struct Call));
}
Assuming calloc succeeded, calls now points to a memory block that contains space for a single struct Call, which includes space for the char pointer and int. However, country itself is still an unintialized pointer, and you must allocate space for it or point it to something already-allocated before you can safely dereference it
calls->country = malloc(25);
if (calls->country == NULL) exit(-1); // handle error how you want
strcpy(calls->country, "Portugal");
printf("%s\n", calls->country); // prints Portugal
or something like
char myCountry[] = "Spain";
calls->country = myCountry;
myCountry[0] = 'X';
printf("%s\n", calls->country); // prints Xpain
Also see Do I cast the result of malloc?
You need to allocate space for the struct and for char array.
You probably want to dynamically add calls to the array so you need to know the size of the array as well:
typedef struct Call{
char *country;
int duration;
}Call;
typedef struct
{
size_t size;
Call call[];
}Calls_t;
Calls_t *addCall(Calls_t *calls, const int duration, const char *country)
{
size_t newsize = calls ? calls -> size + 1 : 1;
calls = realloc(calls, sizeof(*calls) + newsize * sizeof(calls -> call[0]));
if(calls)
{
calls -> size = newsize;
calls -> call[newsize - 1].country = malloc(strlen(country) + 1);
if(!calls -> call[newsize - 1].country)
{
/* error handling */
}
strcpy(calls -> call[newsize - 1].country, country);
calls -> call[newsize - 1].duration = duration;
}
return calls;
}
void printCalls(const Calls_t *calls)
{
if(calls)
for(size_t i = 0; i < calls -> size; i++)
printf("Call %zu: Country:%s Duration:%d\n", i + 1, calls -> call[i].country, calls -> call[i].duration);
}
int main(void)
{
Calls_t *calls = NULL, *tmp;
tmp = addCall(calls, 10, "Poland");
if(tmp) calls = tmp;
tmp = addCall(calls, 20, "UK");
if(tmp) calls = tmp;
tmp = addCall(calls, 30, "US");
if(tmp) calls = tmp;
printCalls(calls);
/* free allocated memory */
}
https://godbolt.org/z/Kb5bKMfYY
I have to dynamically allocate memory using these two functions but I keep getting a segfault. The code takes in strings from a file. I need to dynamically allocate memory for a specific number of monsters using structs, pointers and malloc.
typedef struct monster {
char *name;
char *element;
int population;
} monster;
monster* createMonster(char *name, char *element, int population){
//Copying the data into the monster
monster *temp =(monster*) malloc(sizeof(monster));
strcpy(temp->name, name);
strcpy(temp->element, element);
strcpy(temp->population, population);
return temp;
free(temp);
}
monster** readMonsters(FILE* infile, int *monsterCount){
//getting monster count and creating temp pointers
monster **temp = NULL;
char m_word [8];
fscanf(infile, "%d", monsterCount);
fscanf(infile, "%s", m_word); //reading the word monster to skip it
char* temp_name;
char* temp_element;
int temp_pop;
//allocating memory and creating an array of monster pointers * mcount
temp = (monster**)malloc(*monsterCount * sizeof(monster*));
for(int i = 0; i < monsterCount; i++){
fscanf(infile, "%s",temp_name);
fscanf(infile, "%s",temp_element);
fscanf(infile, "%d",temp_pop);
monster *monster_temp = createMonster(temp_name, temp_element, temp_pop);
temp[i]->name = monster_temp->name;
temp[i]->element = monster_temp->element;
temp[i]->population = monster_temp->population;
}
return temp;
}
You haven't posted the definition of struct monster.
If struct monster contains a lot of char* and you are assigning a char* to it, that char* needs to be allocated somewhere. It doesn't look like temp_name and temp_element have been allocated, which would cause a crash on the scanf.
your code segfault because you write at uninitialized and unallocated pointers
you directly write with strcpy name and element field of your struct but these two field point at unknow location
also, you try strcpy an integer, directly assign it : temp->population = population ;
finally you cannot return temp and free temp, if you return it it will be reused, you must not free it, hopefully the free is never reach as you exit the function one line before :)
for storing your strings into the struct, you have some possibilities
declare them as array of char in your structure : char name[64]
use a buffer in your structure and set the name and element field point on part of it
malloc them with strlen of original strings before the copy
directly point name and element vars of your createMonster function to the pointer, it will use original memory, but it's not suitable here as they come from temporary memory
an example of create monster function using a static common buffer for your strings (untested) :
#define MONSTER_MAX_BF 64
typedef struct monster {
char *name;
char *element;
int population;
char bf[MONSTER_MAX_BF];
} monster;
monster* createMonster(char *name, char *element, int population){
monster *temp =(monster*) malloc(sizeof(monster));
char * lastBf = temp->bf + (MONSTER_MAX_BF - 1); // buffer last char
char *bfp = bf, *p ;
// copy name
temp->name = bfp ;
p = name ;
while( *p && *bfp != lastBf ) *bfp++ = *p++ ;
*bfp++ = 0;
// copy element
temp->element = bfp ;
p = element ;
while( *p && *bfp != lastBf ) *bfp++ = *p++ ;
*bfp = 0;
temp->population = population ;
return temp;
}
I have a struct called Person, that contains two attributes - first and last name.
After successfully dynamic allocation of memory for a variable of Person type, giving values to the attributes I would like to free the memory, but I keep getting a runtime error (the program window just crashes)
this it the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char firstName[15];
char lastName[15];
} Person;
void main(){
int len = 0;
char firstName[]="danny", lastName[]="johnes";
Person *temp = (Person*)malloc(sizeof(Person));
if (temp == NULL)
return;
len = strlen(firstName);
temp->firstName[len] = (char*)malloc(sizeof(char)*(len));
if (temp->firstName == NULL)
return;
strcpy(temp->firstName, firstName);
len = strlen(lastName);
temp->lastName[len] = (char*)malloc(sizeof(char)*(len));
if (temp->firstName == NULL)
return;
strcpy(temp->lastName, lastName);
freePerson(temp);
system("pause");
return;
}
This is the function I use to free the memory:
void freePerson(Person* ps) {
if (ps != NULL) {
free(ps->firstName);
free(ps->lastName);
free(ps);
}
}
All I want the code to do - is to store the name in a dynamically allocated structure, and free it.
Later on, I plan to replace the hard-coded names with values inputed from file.
Any ideas about the error? Thank you.
You have already space allocated for firstName, so you have to copy the name within the size constraits (15 bytes). You can do this best with snprintf like this:
snprintf(temp->firstName, sizeof(temp->firstName), "%s", firstName);
Same goes for lastName. Mind that both might be truncated if the length exceeds the size of the field.
The other option is to allocate the fields dynamically. Then your struct members should be pointers, not char arrays:
typedef struct {
char *firstName;
char *lastName;
} Person;
You can then allocate and assign the names like this:
temp->firstName = strdup(firstName); // (same for lastName)
But mind that you have to free these fields seperately if you want to free the whole item.
If you don't want to specify a maximum size for the names in the structure, you need to declare them as pointers, not arrays.
typedef struct {
char *firstName;
char *lastName;
} Person;
Then you should assign the result of malloc() to the member, without indexing it. You also need to add 1 to strlen(firstName), to make space for the null terminator.
temp->firstName = malloc(strlen(firstName)+1);
if (temp->firstName == NULL) {
return;
}
strcpy(temp->firstName, firstName);
This is how I would write this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FIRSTNAME_MAXLEN 15
#define LASTNAME_MAXLEN 15
typedef struct
{
char firstName[FIRSTNAME_MAXLEN+1];
char lastName[LASTNAME_MAXLEN+1];
} person_t;
void freePerson(person_t *ps) {
if (ps) {
free(ps); ps=NULL;
}
}
int main(){
const char *firstName="danny";
const char *lastName="johnes";
person_t *temp = calloc(1, sizeof(person_t));
if (!temp) return 1;
strncpy(temp->firstName, firstName, FIRSTNAME_MAXLEN);
strncpy(temp->lastName, lastName, LASTNAME_MAXLEN);
printf("test: firstname: %s\n", temp->firstName);
printf("test: lastname: %s\n", temp->lastName);
freePerson(temp);
return 0;
}
You allocate enough room on the heap and cleanup things with calloc(), then you copy your string with strncpy() limiting to the bytes reserved and avoiding buffer overflow. At the end you need to free() the memory returned by calloc().
Since you allocated char firstName[] and char lastName[] inside your struct you don't need to reserve other memory with malloc() for those members, and you also don't need to free() them.
At least 5 issues:
To duplicate a string, insure allocation includes enough room for the characters including the null character.
Otherwise the strcpy() writes outside the allocation which is undefined behavior (UB).
len = strlen(firstName);
// temp->firstName[len] = (char*)malloc(sizeof(char)*(len ));
temp->firstName = (char*)malloc(sizeof(char)*(len + 1));
// + 1
...
strcpy(temp->firstName, firstName);
Same for lastName.
Also assign to the pointer, not the char. #Barmar
Person members are arrays. For dynamic allocation, they should be pointers. #NthDeveloper
typedef struct {
// char firstName[15];
// char lastName[15];
char *firstName;
char *lastName;
} Person;
2nd test is wrong
// if (temp->firstName == NULL)
if (temp->lastName == NULL)
int vs. size_t.
int len = 0; assumes the string length fits in a int. Although this is exceedingly common, the type returned from strlen() is size_t. That unsigned type is right-sized for array indexing and sizing - not too wide, not too narrow. Not a key issue in this learner code.
// int len = 0;
size_t len = 0;
Tip: cast not needed. Allocate to the referenced object, not the type. Easier to code right, review and maintain.
// Person *temp = (Person*)malloc(sizeof(Person));
Person *temp = malloc(sizeof *temp);
// temp->firstName[len] = (char*)malloc(sizeof(char)*(len + 1));
temp->firstName = malloc(sizeof *(temp->firstName) * (len + 1));
Tip: Although not C standard, many platforms provide strdup() to allocated and copy strings. Sample strdup() code.
temp->firstName = strdup(firstName);
Tip: Likely the most valuable one: A good compiler with warnings well enabled should have warned about temp->firstName[len] = (char*)malloc(sizeof(char)*(len)); as it is a questionable type mis-match in the assignment. These warnings save you and us all time. Insure your next compilation has all warning enabled.
I have a structure:
struct student{
int roll_no;
char *name = malloc(25 * sizeof(char));;
char *phone_no = malloc(10 * sizeof(char));;
char *dob = malloc(10 * sizeof(char));;
}*s1;
int main(){
s1 = malloc(5 * sizeof(student)); //array of student
//.....
}
What is appropriate code for the complete loop for allocating an array of student of size 'n' and then de-allocating it afterwards?
Note: The question here deals with allocation and de-allocation of elements of the instance of a structure.
This...
typedef struct student{
int roll_no; // (the following illegal syntax commented out)
char *name; // = malloc(25 * sizeof(char));;
char *phone_no; // = malloc(10 * sizeof(char));;
char *dob; // = malloc(10 * sizeof(char));;
}*s1;
...from what is being described as the need, (minus the illegal assignment statements) could probably better be formed as:
typedef struct {
int roll_no;
char *name; //needs memory
char *phone; //needs memory
char *dob; //needs memory
}STUDENT;
Then, use the new variable type: STUDENT, to create the instances of the struct as needed. Your OP indicates you need 5:
STUDENT s[5]; //Although this array needs no memory, the
//members referenced by it do
//(as indicated above)
Now, all that is necessary is to create memory for the 3 members that require it, in each of the 5 instances.
for(i=0;i<5;i++)
{
s[i].name = calloc(80, 1); //calloc creates AND initializes memory.
s[i].phone = calloc(20, 1); //therefore safer than malloc IMO.
s[i].dob = calloc(20, 1); //Also, change values as needed to support actual
//length needs for name, phone and dob
}
// Use the string members of s[i] as you would any other string, But do not
// forget to free them when no longer needed.
...
for(i=0;i<5;i++)
{
free(s[i].name);
free(s[i].phone);
free(s[i].dob);
}
Note, because of the way the array s is created in this example, i.e. with memory on the stack instead of the heap, there is no need to free it.
One other note, the example code above focused on a method to create memory for the char * members of your struct array, but when actually coding for keeps, the return of [m][c][re]alloc should always be checked that memory was created before trying to use the variable. For example:
s[i].name = calloc(80, 1);
if(!s[i].name) //checking that memory was created
{
;//if failed, then handle error.
}
...
In addition to ryyker's answer, if you want to do it dynamically:
#include <stdlib.h>
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main()
{
int i, student_count = 5;
struct student ** s = malloc(sizeof(struct student *) * student_count);
if (s)
{
for (i = 0; i < student_count; ++i)
{
s[i] = malloc(sizeof(struct student));
if (s[i])
{
//set up student's members
}
}
for (i = 0; i < student_count; ++i)
{
//free student's members before the next line.
free(s[i]);
}
free(s);
}
return 0;
}
You must free everything you malloc, and as mentioned in the comments you cannot malloc inside the struct.
#include <stdio.h>
#include <stdlib.h>
#define NUM_STUDENTS 5
struct student{
int roll_no;
char *name;
char *phone;
char *dob;
};
int main(void)
{
int i;
// if this was me, I would simply replace this with
// struct student s[NUM_STUDENTS];, but the goal here is to illustrate
// malloc and free
struct student* s = malloc(sizeof(struct student) * NUM_STUDENTS);
if (s == NULL) // handle error
for (i=0; i<NUM_STUDENTS; i++)
{
// sizeof(char) is guaranteed to be 1, so it can be left out
s[i].name = malloc(25);
if (s[i].name == NULL) // handle error
s[i].phone = malloc(10);
if (s[i].phone == NULL) // handle error
s[i].dob = malloc(10);
if (s[i].dob == NULL) // handle error
}
// do stuff with with the data
....
// time to clean up, free in the reverse order from malloc
for (i=0; i<NUM_STUDENTS; i++)
{
// the dob, phone, name order here isn't important, just make sure you
// free each struct member before freeing the struct
free(s[i].dob);
free(s[i].phone);
free(s[i].name);
}
// now that all the members are freed, we can safely free s
free(s);
return 0;
}
User Abhijit gave an answser that was in the right direction, but not complete. His answer should have been:
typedef struct STUDENT{
int roll_no;
char *name;
char *phone;
char *dob;
}student;
void example(int n_students)
{
student **s;
int i;
s= malloc(n_students * sizeof(student *));
for (i=0; i<n_students; i++)
{
s[i]= malloc(sizeof(student));
s[i]->name= malloc(25);
s[i]->phone= malloc(10);
s[i]->dob= malloc(10);
}
// now free it:
for (i=0; i<n_students; i++)
{
free(s[i]->name);
free(s[i]->phone);
free(s[i]->dob);
free(s[i]);
}
free(s);
}
So I'm trying to learn C right now, and I have some basic struct questions I'd like to clear up:
Basically, everything centers around this snippet of code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN 127
typedef struct {
char name[MAX_NAME_LEN + 1];
unsigned long sid;
} Student;
/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
return s->name; // returns the 'name' member of a Student struct
}
/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct | 'name' is a pointer to the first element of a char array (repres. a string)
char temp;
int i;
for (i = 0, temp = &name; temp != '\0'; temp++, i++) {
*((s->name) + i) = temp;
}
/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
return s->sid;
}
/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
s->sid = sid;
}
I've commented up the code in an attempt to solidify my understanding of pointers; I hope they're all accurate.
Also, I have another method,
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
which I'm sure is wrong in some way... I also think my setName is implemented incorrectly.
Any pointers? (no pun intended)
This is very wrong. If you insist on not using strcpy do something like this (not tested)
int iStringLength = strlen(name);
for (i = 0; i < iStringLength; i++) {
s->name[i] = name[i];
}
but make sure that the length is not longer than your array size.
This is also wrong
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
because the s object is destroyed when the function exits - it is local to the function scope and yet you return a pointer to it. So if you try to access the struct using this pointer it will not be valid as the instance no longer exists. If you want to do this you should dynamically allocate it using malloc . Alternatively do not return a pointer at all and use the alternative option of #Andrew .
In your "another method" you are locally declaring Student s, which will dynamically allocate space (usually on the stack) and you are returning that address on completion.
However, that stack-space will be released on the return, so there is no guarantee that the data is uncorrupted - in fact the likelyhood is that it will be!
Declare Student s in the call to your method, and pass the pointer to makeAndrew:
void makeAndrew(Student *s) {
setName( s, "Andrew");
setStudentID( s, 12345678);
}
...
Student s;
makeAndrew( &s );
...
Your function makeAndrew returns pointer to a local variable. It is only valid before the scope ends, so as soon as the function finishes, it will change when the memory gets overwritten - i. e. almost instantly. You would have to allocate it dynamically (using Student *s = new Student;, or if you really want to stick to pure C, Student *s = malloc (sizeof Student );, and then free it outside the function after it is not needed to avoid memory leak.
Or do it as Andrew suggested, it's less error-prone.
I would change the makeAndrew() function to just return a struct, not a pointer to a struct to correct the error with respect to returning a pointer to a temporary variable:
Student makeAndrew(void)
{
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return s;
}
Student aStudent = makeAndrew();
Your setName does have an error with respect to temp, which should be a char *, since you are incrementing it in your loop to point to another character in the input c-string. I think it was missing the null termination as well. And as you mention in your comment, there should be a check for overflow of the name char array in Student:
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |
// 'name' is a pointer to the first element of a char array (repres. a string)
const char *temp;
int i;
for (i = 0, temp = name; *temp != '\0' && i <= MAX_NAME_LEN; temp++, i++)
{
*((s->name) + i) = *temp;
}
s->name[i] = '\0';
}
You can use strncpy to simplify setName:
void setName2(Student *s,const char *name)
{
#include <string.h>
strncpy(s->name, name,MAX_NAME_LEN);
s->name[MAX_NAME_LEN] = '\0';
}