2

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!

charliekelly
  • 456
  • 1
  • 7
  • 22
  • There are many problems with this code, but I'm also not quite sure what you intend. For example, is it a requirement to allocate on the heap using malloc? If not, I'd change the definition of `people` to simply allocate on the stack. However, that makes the `insert()` function mostly unnecessary – Jared Dykstra Nov 10 '15 at 00:02
  • 1
    `(*people[*nextfreeplace]).name` - it looks like you are guessing combinations of brackets and stars until the compiler stops complaining. This is not a good way to learn C! – M.M Nov 10 '15 at 01:28

4 Answers4

2

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.

Community
  • 1
  • 1
anatolyg
  • 26,506
  • 9
  • 60
  • 134
1

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

TheRealChx101
  • 1,468
  • 21
  • 38
1

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;
kdopen
  • 8,032
  • 7
  • 44
  • 52
  • "the name of an array is synonymous with its address" should be "the name of an array is *converted to* the address of its first element, in most contexts". An example of a context where this conversion does not happen would be when used with the `sizeof` operator, or the `&` operator. – M.M Nov 10 '15 at 01:31
-1

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);

  • A pointer-to-pointer-to-pointer-to-person would be `person ***`, and would be much less confusing. The problematic type is actually a pointer to an array. – anatolyg Nov 10 '15 at 00:09
  • When a *x[] passed to a function, from the compiler's point of view, as it see it on the stack, it is just a **x. – Aleksi Romanov Nov 10 '15 at 00:29
  • @AleksiRomanov that's true but the problem is with `&people` which is not a `**x` or a `***x` or anything like that. – M.M Nov 10 '15 at 01:32