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.
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;
}
I don't love this, but I have a struct with nearly 45 members inside; all are characters or character arrays. That said, I am going to need to optimize the way I initialize each struct. Ordinarily, I would pass the entire object into my init_struct() function, but I feel like that is not the best way to do this.
How would I create and use a pointer to the struct to accomplish this?
Old Method would look something like this:
void init_struct(struct general){
...initialize members...
}
int main(){
struct general[10];
for(int i = 0 ; i < 10 ; ++i){
init_struct(general[i];
}
}
Since this struct is so large, as I said nearly 45 members inside it, I think a point to the struct would go a long way in optimizing this process. How would I accomplish that?
Just in case you need, here is the typedef for my struct
typedef struct
{
//Basically, everything we want to read from HUDL should be here...
int play_num;
char down;
char dist[3];
char ydln[4];
char gnls[3];
char hash[3];
char home[20];
char away[20];
char odk[2];
char qtr[2];
char series[3];
char result[20];
char penalty[20];
char act_cb[20]; //How do they act post-snap
char act_dl[20];
char act_lb[20];
char act_ol[20];
char act_qb[20];
char act_rb[20];
char act_saf[20];
char aln_cb[20]; //How do they align pre-snap
char aln_dl[20];
char aln_lb[20];
char aln_ol[20];
char aln_qb[20];
char aln_rb[20];
char aln_saf[20];
char aln_wr[20];
char blitz[20];
char box_cnt[3];
char saf_count[20];
char coverage[20];
char cvr_basic[20];
char def_front[20];
char mtn_def[20];
char num_rush[3];
char off_form[20];
char form_var[20];
char motion[20];
char off_pro[20];
char off_play[20];
char play_var[20];
char personnel[20];
char play_type[20];
char time[2];
char score_diff[4];
char field_zone[2];
char dd_type[2];
char form_strength[2];
} HUDL; // MAXIMUM of 63 Members
There's a couple of things wrong on your code.
First of, your function definition is wrong because you omit the parameter name. Your function definition should look like this:
void init_struct(struct general mygeneralstruct){}
Alternatively, you could use an alias for your struct using typedef, like so:
typedef struct {
int a;
} general;
In which case, your function declaration could look like this:
void init_struct(general mygeneralstruct){}
You have the same problem when you declare your array of structures. You omit the name of your variable. Instead of
struct general[10];
it should be
struct general mygeneralstruct[10]
or
general mygeneralstruct[10](typedef)
Finally, you can't change your array of structures by passing each structure's value to the function. You need to pass each structure's address instead.
Your function declaration should then be(using typedef):
void init_struct(general* mygeneralstruct){}
and the code in the loop:
init_struct(&mygeneralstruct[i]);
To pass a pointer to your array element, you just prefix the parameter with &, make sure you declare the function correctly:
void init_struct(HUDL* pGeneral){
if ( pGeneral != NULL ) {
//This will ensure the entire structure contains '0'
memset(pGeneral, 0, sizeof(HUDL));
...initialize members...
}
}
int main(){
HUDL general[10];
for( int i=0; i<(sizeof(general) / sizeof(general[0])); i++ ) {
init_struct(&general[i]);
}
}
I'm not sure why you haven't used the typedef 'HUDL' makes life a lost easier and code easier to read.
A slightly cleaner and better approach would be to have a constructor and destructor function to allocate memory dynamically to structure and free it after use.
static void HUDL_destroy(HUDL* ptr)
{
if(ptr)
{
//...any other clean up that needs to be done goes here..
free(ptr);
}
}
static HUDL* HUDL_create()
{
HUDL* ptr = malloc(sizeof(HUDL));
if(!ptr)
return NULL;
//do initialization bits...
init_struct(ptr);
return ptr;
}
int main()
{
//allocate and initialise structure
HUDL *general = HUDL_create();
//do stuff...
//free structure after use
HUDL_destroy(general);
}
You might need an array of pointers in your case. So modify your main() accordingly.
int main()
{
//we need an array of structure pointers
HUDL* general[SIZE];
//allocate and initialize structure
for(int i=0; i<SIZE; i++)
general[i] = HUDL_create();
//do stuff...
//free structure after use
for(i=0; i<SIZE; i++)
HUDL_destroy( general[i] );
}
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);
Is it possible to create a struct containing two dynamically size arrays in c?
I have something like this:
#define MAX_DATA 512
struct Address {
int id;
int set;
char name[MAX_DATA];
char email[MAX_DATA];
};
I'd like MAX_DATA to be defined at run time.
I have seen the struct hack:
How to include a dynamic array INSIDE a struct in C?
But I think this only works for one field per struct?
This code is from http://c.learncodethehardway.org/book/ex17.html
The extra credit section near the bottom of that page contains the bit about changing the sizes to be dynamic.
I once did this:
struct Thing {
int Number;
char *MoreBytes;
char Bytes[]
}
Thing *MakeThing(int nBytes, int nMoreBytes)
{
Thing *th = malloc(sizeof(Thing) + nBytes + nMoreBytes);
// Error checking is for grrrlz.
th->Number = 42;
th->MoreBytes = th->Bytes + nBytes;
return th;
}
Thus the array th->Bytes actually holds both "arrays", and the pointer th->MoreBytes tells us
where one array ends and another begins.
It works (at least for GCC 4.7.2) if you put your struct Address definition in a function, like this:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
int len = atoi(argv[1]);
struct Address {
int id;
char name[len];
int set;
char email[len];
};
printf("sizeof(struct Address) = %zu\n", sizeof(struct Address));
exit(EXIT_SUCCESS);
}
Testing:
$ ./a.out 10
sizeof(struct Address) = 32
$ ./a.out 20
sizeof(struct Address) = 48
struct Address
{
int id;
int set;
char *name;
char *email;
};
Now in the main() function, Use some variable, lets say len to store length of the array, and dynamically allocate required memory using malloc().
int len;
struct Address Add;
printf("Enter the lenght of the array you want?");
scanf("%d",&len);
Add.name=(char *)malloc(len);
Add.email=(char *)malloc(len);
otherwise you can add len as the member of the struct Address
struct Address
{
int id;
int set;
int len;
char *name;
char *email;
};
Now in main()
struct Address Add;
printf("Enter the lenght of the array you want?");
scanf("%d",&Add.len);
Add.name=(char *)malloc(Add.len);
Add.email=(char *)malloc(Add.len);
You can do this using the struct hack, now known as a flexible array. It just requires you to pack both arrays into the flexible part of the struct.
Suppose that you want the arrays to be of length N and M respectively. Then allocate a flexible array as if you were allocating a single array of length N+M. Then use indices 0..N-1 for the first array, and indices N..N+M-1 for the second array.
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.