This program is supposed to create a struct array containing the name and age values from the hard coded name and age arrays at the start of the code.
I've been explicity asked to declare the array in the main function and then allocate memory to it within the insert function. The program compiles fine and the output i'm supposed to get is:
Name: Simon
Age: 22
Name: Suzie
Age: 24
Name: Alfred
Age: 106
Name: Chip
Age: 6
etc. etc.
However the output I get is something like this:
Name: Simon
Age: 22
Name: (null)
Age: 33
Name: Suzie
Age: 24
Name: (null)
Age: 33
Name: Suzie
Age: 24
.....
segmentation fault.
Some of the names appear twice, some of the names are null, and there is a segmentation fault at the end of the output.
Any help would be greatly appreciated. many thanks.
#include <stdio.h>
#include <stdlib.h>
/* these arrays are just used to give the parameters to 'insert',
to create the 'people' array
*/
#define HOW_MANY 7
char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim",
"Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};
/* declare your struct for a person here */
struct person {
char *name;
int age;
};
static void insert(struct person **arr, char *name, int age)
{
//initialise nextfreeplace
static int nextfreeplace = 0;
//allocate memory
arr[nextfreeplace] = malloc (sizeof(struct person));
/* put name and age into the next free place in the array parameter here */
arr[nextfreeplace]->name = name;
arr[nextfreeplace]->age = age;
/* modify nextfreeplace here */
nextfreeplace++;
}
int main(int argc, char **argv)
{
/* declare the people array here */
struct person *people;
for (int i = 0; i < HOW_MANY; i++)
{
insert (&people, names[i], ages[i]);
}
/* print the people array here*/
for (int i = 0; i < HOW_MANY; i++)
{
printf("Name: %s \t Age: %i \n", people[i].name, people[i].age);
}
return 0;
}
In your code, you have
#define HOW_MANY 7
/* ... */
struct person {
/* ... */
};
static void insert(struct person **arr/* ... */) {
static int nextfreeplace = 0;
/* ... */
arr[nextfreeplace] = malloc(sizeof(struct person));
/* ... */
nextfreeplace++;
}
int main(int argc, char **argv) {
/* ... */
struct person *people;
for (int i = 0; i < HOW_MANY; i++) {
insert(&people/* ... */);
}
/* ... */
return 0;
}
The problem is that you define a variable named people as a pointer. Then you pass the address of that pointer to insert. Since local variables are (usually) allocated on the stack, your allocations made in insert overwrite parts of it.
Assume you have
struct person *people;
struct person *otherpeople;
Then, when you have nextfreeplace == 0, you assign to arr[0] == *arr, which is fine. But for nextfreeplace == 1, you assign to arr[1] == *(arr+1) == otherpeople.
This type of bug is called a buffer overflow.
To fix this bug, you would need to use struct person *people[HOW_MANY]; and insert(people/* ... */);.
As a side note: You should also free the memory you allocated and do not need anymore using free.
Related
I am a noob to C.I wrote a program that my array people is now an array of pointers to structs. And insert to call malloc to create a new struct and set the correct array element pointing to it.
HERE IS my code.
#include <stdio.h>
/* these arrays are just used to give the parameters to 'insert',
to create the 'people' array
*/
#define HOW_MANY 7 char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim","Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};
/* declare your struct for a person here */
typedef struct{
char* name;
int age;
} person;
static void insert( person *people[], char *name, int age,int i) {
/* put name and age into the next free place in the array parameter
here */
people[i] = malloc(sizeof(person));
people[i]->name = name;
people[i]->age = age;
/* modify nextfreeplace here */
}
int main(int argc, char **argv) {
/* declare the people array here */
person *people[7];
for (int index=0;index < HOW_MANY;index=index+1) {
insert (&people[index], names[index], ages[index],index);
}
/* print the people array here*/
for(int index=0;index < HOW_MANY;index=index+1) {
printf("name: %s, age: %i\n",
people[index]->name, people[index]->age);
}
return 0;
}
And I get errors
part2.c:23:5: warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
people[i] = malloc(sizeof(person));
^ part2.c:23:17: warning: incompatible implicit declaration of built-in function ‘malloc’ [enabled by default]
people[i] = malloc(sizeof(person));
Can anyone help me? appreciate
I have observed a few issues which are causing these problems. Check the code which I have given below.
There in the comments, I have mentioned where to make changes.
You are using the malloc function without including the stdlib file!
See this code, I have tested it in dev-cpp and it's now working.
#include <stdio.h>
#include <stdlib.h>
/* these arrays are just used to give the parameters to 'insert',
to create the 'people' array
*/
#define HOW_MANY 7
char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim","Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};
/* declare your struct for a person here */
typedef struct{
char* name;
int age;
} person;
/* declare the people array here */
person *people[7];
person* insert(char *name, int age,int i) {
/* put name and age into the next free place in the array parameter
here */
people[i] = malloc(sizeof(person));
people[i]->name = name;
people[i]->age = age;
/* modify nextfreeplace here */
}
int main(int argc, char **argv) {
int index;
for (index=0;index < HOW_MANY;index=index+1) {
insert(names[index], ages[index],index);
}
/* print the people array here*/
for(index=0;index < HOW_MANY;index=index+1) {
printf("name: %s, age: %i\n",
people[index]->name, people[index]->age);
}
return 0;
}
Please see my answer below and compare with your code where you need modification and also try to understand what my code is doing. If you are not clear with any part of my code please feel free to ask me question.
char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim","Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};
/* declare your struct for a person here */
typedef struct{
char* name;
int age;
} person;
static void insert( person *people[], char *name, int age,int i) {
/* put name and age into the next free place in the array parameter
here */
people[i] = malloc(sizeof(person));
people[i]->name = name;
people[i]->age = age;
/* modify nextfreeplace here */
}
int main(int argc, char **argv) {
/* declare the people array here */
person *people[7];
for (int index=0;index < HOW_MANY;index=index+1) {
insert(people, *(names+index), ages[index],index);
}
/* print the people array here*/
for(int index=0;index < HOW_MANY;index=index+1) {
printf("name: %s, age: %i\n",
people[index]->name, people[index]->age);
}
return 0;
}
The purpose of this program is to assign the names to their corresponding ages using pointers.
#include <stdio.h>
#include <stdlib.h>
/* these arrays are just used to give the parameters to 'insert',
to create the 'people' array
*/
#define HOW_MANY 7
char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim",
"Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};
/* declare your struct for a person here */
typedef struct {
char *name;
int age;
} person;
static void insert(person *people[], char *name, int age, int *nextfreeplace)
{
/* creates memory for struct and points the array element to it. */
people[*nextfreeplace] = malloc(sizeof(person));
/* put name and age into the next free place in the array parameter here */
(*people[*nextfreeplace]).name = name;
(*people[*nextfreeplace]).age = age;
/* modify nextfreeplace here */
(*nextfreeplace)++;
}
int main(int argc, char **argv)
{
/* declare the people array here */
person *people[HOW_MANY];
int nextfreeplace = 0;
for (int i = 0; i < HOW_MANY; i++)
{
insert (&people, names[i], ages[i], &nextfreeplace);
}
/* print the people array here*/
for (int i = 0; i < HOW_MANY; i++) {
printf("Name: %s. Age: %d\n", (*people[i]).name, (*people[i]).age);
}
/* Releases the memory allocated by malloc */
for (int i = 0; i < HOW_MANY; i++) {
free(people[i]);
}
return 0;
}
It works perfectly, but when I compile it I get two warnings.
arrays.c: In function ‘main’:
arrays.c:41:13: warning: passing argument 1 of ‘insert’ from incompatible pointer type [-Wincompatible-pointer-types]
insert (&people, names[i], ages[i], &nextfreeplace);
^
arrays.c:19:13: note: expected ‘person ** {aka struct <anonymous> **}’ but argument is of type ‘person * (*)[7] {aka struct <anonymous> * (*)[7]}’
static void insert(person *people[], char *name, int age, int *nextfreeplace)
I'm new to pointers and C in general and would like some help explaining why I get these warnings and how to get rid of them. Thanks!
TL; DR
Use people instead of &people.
Long explanation
Here is what the warning messages say:
Your function insert expects a parameter of type person ** (a pointer to pointer to person). Your code sends it a parameter of different type: person * (*)[7], which is a C way for "a pointer to an array of 7 pointers to person".
(you can use the site http://cdecl.org to discover that: enter struct person * (*people)[7] in its field, and it will translate it to English)
If you send your array, and not a pointer to it, to your insert function, the compiler will regard the name people as a "pointer to pointer to person", which in this context is a special case of "array of pointers to person". This process is called "decay" of array to a pointer, and is explained here.
You can also do this:
/* declare your struct for a person here */
typedef struct {
char *name;
int age;
} person, *people_t;
And then
static void insert(people_t people[], char *name, int age, int *nextfreeplace){...}
Then
people_t people[HOW_MANY];
int nextfreeplace = 0;
for (i = 0; i < HOW_MANY; i++){
insert (people, names[i], ages[i], &nextfreeplace);
}
Compiler: Visual Studio 2010
This is actually a single warning, shown over two lines (the source of the warning at line 41, and the declaration causing the problem at line 19).
You can clear the warning by removing the ampersand from the call to insert, thus
insert(people, names[i], ages[i], &nextfreeplace);
In C, the name of an array is synonymous with its address.
Also, to clear up the <anonymous> tag in the warnings, a common idiom when typedefing structures is the following:
typedef struct <name>
{
...
} <name>;
which in your case would be:
typedef struct person {
char *name;
int age;
} person;
You get these warning because the "insert" expects pointer-to-pointer-to-person, but gets just a pointer-to-pointer-to-pointer-to-person.
In line 41, get rid of "&" from "&people", like in:
insert (people, names[i], ages[i], &nextfreeplace);
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
So I just started learning struct type in C but I'm a bit confused. I have a pretty long program which I'm working on and I'm not sure to how to insert a name and age into the next unused element in the arrray using a static variable (e.g. called nextinsert) inside the function to remember where the next unused element is.
This is the my code for the insert function.
static void insert (struct person people[], char *name, int age)
{
static int nextfreeplace = 0;
static int nextinsert = 0;
/* put name and age into the next free place in the array parameter here */
For your question "how to insert a name and age", use:
strcpy(people[nextfreeplace],name);
people[nextfreeplace].age = age;
You may need to include string.h for strcpy.
Why not make it simpler: instead of trying to keep track of the index inside the insert function, you alreay have the index inside the main function. Thus:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* these arrays are just used to give the parameters to 'insert',
to create the 'people' array */
#define HOW_MANY 7
#define MAXSTRLEN 32
/* declare your struct for a person here */
struct person
{
char name [MAXSTRLEN];
int age;
};
static void insert (struct person *people, char *name, int age)
{
strncpy(people->name, name, MAXSTRLEN);
people->age = age;
}
int main(int argc, char **argv) {
// Move arrays here; if they are global instead,
// there would be need to pass name and age to insert()
char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim",
"Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};
/* declare the people array here */
struct person people[12];
int i;
for (i =0; i < HOW_MANY; i++)
{
insert (&people[i], names[i], ages[i]);
}
/* print the people array here*/
for (i =0; i < HOW_MANY; i++)
{
printf("%s\n", people[i].name);
printf("%d\n", people[i].age);
}
return 0;
}
The people->name syntax is a shorthand for (*people).name. That is, you dereference the pointer to get to the actual struct (*people), and then access the struct number; because of operator precedence rules you need the parenthesis around *people.
I'm not sure how familiar you are with pointers, but in C, this is very common (passing a pointer to a struct into a function, and then using structure->member inside that function.
Of course, if your whole "exercise" revolves around learning about static variables, this may be of little value. But what I have here is likely preferred to keeping a static variable inside the function for array indexing.
help needed printing array of pointers to structs
where am i going wrong ? please help
include <stdio.h>
include <stdlib.h>
define HOW_MANY 7
char *names[HOW_MANY]= {"Simon", "Suzie", "Alfred", "Chip", "John", "Tim",
"Harriet"};
int ages[HOW_MANY]= {22, 24, 106, 6, 18, 32, 24};
struct person
{
char *name;
int age;
};
static void insert (struct person *people[], char *name, int age) {
static int nextfreeplace = 0;
typedef struct person newperson;
newperson *structperson = (newperson*)malloc(sizeof(newperson));
(*structperson).name= name;
(*structperson).age = age;
printf("%s",(*structperson).name);
people[nextfreeplace] = &structperson;
printf("%s",(*people[nextfreeplace]).name);
nextfreeplace++;
}
int main(int argc, char **argv) {
struct person *people[HOW_MANY];
for (int c=0; c < HOW_MANY;c++) {
insert (people, names[c], ages[c]);
}
print the people array here
for (int i=0; i < HOW_MANY;i++) {
printf("%s \n",&(*people[i]).name);
}
return 0;
}
Where you malloc, you are declaring your structperson as a value instead of a pointer. Then you try to refer to it from then on as a pointer (ie dereferencing it with the asterisk).
Here is how I would write it. I make a number of changes, such as remove the static var (you should handle the array where your are assigning it, your function shouldn't be storing the state of the array, then no one else can ever use it).
Lots of style problems:
Don't cast the return value of malloc.
Instead of passing sizeof(newperson) to malloc, use sizeof *structperson.
Use the -> operator, i.e. structperson->name instead of (*structperson).name.
Clean up the (confusing a misleading) names you've used for your typedef and variables.
In place of HOW_MANY, you might use sizeof names/sizeof names[0].
i want to add the data to structs which are person and then make an array of pointers to the person and then print them out. currently i am getting output which is not readable e.g 11112012.