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;
}
Related
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.
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 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'.
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.