2

I have a pointer to a struct of type Map defined in an external header file:

typedef struct {
    char *squares; //!< A pointer to a block of memory to hold the map.
    int   width;   //!< The width of the map pointed to by squares.
    int   height;  //!< The height of the map pointed to by squares.
} Map;

The pointer is initialised as follows:

    struct Map *map_ptr;    
    map_ptr = create_map(*w_ptr, *h_ptr);
    // create_map returns Map*, w_ptr and h_ptr are pointers to height and width fields for a map/maze.

How do I go about printing the values of width and height stored within the Map structure which is created in create_map? create_map is held in an external file and the only variable it passes back to main is the pointer to the map.

The following gives an error when compiling ("error: dereferencing pointer to incomplete type")

printf("Height = %d\n", map_ptr->height);

As far as I know, the pointer is valid as the code below prints a memory address:

printf("Pointer address for map = %p\n", map_ptr);
Bradford
  • 107
  • 1
  • 1
  • 9
  • 5
    How does it not work? Does it not do anything? Does it crash? What happens? – icktoofay Dec 30 '12 at 22:19
  • See also [this question](http://stackoverflow.com/questions/612328/difference-between-struct-and-typedef-struct-in-c). – Adam Rosenfield Dec 30 '12 at 22:51
  • C nit: `%p` args must be (cast to) ptr-to-void otherwise you invoke undefined behavior. – Jens Dec 30 '12 at 23:03
  • See also this link, or the sample code below: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fnamspac.htm – paulsm4 Dec 31 '12 at 01:28

4 Answers4

5

Just drop the struct keyword from:

struct Map *map_ptr;    

to:

Map *map_ptr;    

You have declared a nameless struct and typedef'ed it to Map. So when you declare struct Map *map_ptr;, compiler thinks this is another struct called Map.

P.P
  • 117,907
  • 20
  • 175
  • 238
2

You tripped over what is called namespaces in C. There are separate namespaces for

  • typedef names, as you introduced with typedef struct { ... } Map;
  • struct tags, as you introduced with struct Map *map_ptr;
  • plus other namespaces for objects, macro names, ...

The same indentifier can be reused in different namespaces. I recommend to never bother with typedefs for structs. It only hides useful information, and all it does it saving you from writing struct every now and then. If something is a struct or pointer to a struct then I want to know it so I know whether to use -> or . to access the members. Using typedefs defeats this by hiding useful information.

One way to fix your problem is to get rid of the typedef and only use a struct tag with

struct Map {
    char *squares; //!< A pointer to a block of memory to hold the map.
    int   width;   //!< The width of the map pointed to by squares.
    int   height;  //!< The height of the map pointed to by squares.
};
struct Map *map_ptr = ...;
Jens
  • 69,818
  • 15
  • 125
  • 179
  • Very, very good point - thank you. I should emphasize that the C concept of "namespace" does *not* correspond to C++ "namespaces". The two are different. Here's a link: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fnamspac.htm – paulsm4 Dec 31 '12 at 01:28
0

Here is a complete example that might help clarify a few points:

#include <stdio.h>
#include <malloc.h>
#include <string.h>

typedef struct {
    char *squares; //!< A pointer to a block of memory to hold the map.
    int   width;   //!< The width of the map pointed to by squares.
    int   height;  //!< The height of the map pointed to by squares.
} Map;


Map *
create_map ()
{
  printf ("Allocating %d bytes for map_ptr, and %d bytes for map data...\n",
    sizeof (Map), 100);
  Map *tmp = (Map *)malloc(sizeof (Map));
  tmp->squares = (char *)malloc (100);
  strcpy (tmp->squares, "Map data...");
  tmp->width = 50;
  tmp->height = 100;
  return tmp;
}

int 
main(int argc, char *argv[])
{
  Map *map_ptr = create_map();
  printf ("map_ptr->height= %d, width=%d, squares=%s\n",
    map_ptr->height, map_ptr->width, map_ptr->squares);
  free (map_ptr->squares);
  free (map_ptr);
  return 0;
} 

EXAMPLE OUTPUT:

Allocating 12 bytes for map_ptr, and 100 bytes for map data...
map_ptr->height= 100, width=50, squares=Map data...

An alternative approach would be to use "struct Map {...}" instead of the typedef:

EXAMPLE:

struct Map {
    char *squares; //!< A pointer to a block of memory to hold the map.
    int   width;   //!< The width of the map pointed to by squares.
    int   height;  //!< The height of the map pointed to by squares.
} Map;


struct Map *
create_map ()
{
...
  struct Map *tmp = (struct Map *)malloc(sizeof (struct Map));
  ...
}
  ...
  struct Map *map_ptr = create_map();
  printf ("map_ptr->height= %d, width=%d, squares=%s\n",
    map_ptr->height, map_ptr->width, map_ptr->squares);
  free (map_ptr->squares);
  free (map_ptr);
paulsm4
  • 114,292
  • 17
  • 138
  • 190
0

Answer 1:

struct Map *map_ptr; 

to

Map *map_ptr; 

Answer 2:

typedef struct {
    char *squares; //!< A pointer to a block of memory to hold the map.
    int   width;   //!< The width of the map pointed to by squares.
    int   height;  //!< The height of the map pointed to by squares.
} Map;

to

struct Map{
    char *squares; //!< A pointer to a block of memory to hold the map.
    int   width;   //!< The width of the map pointed to by squares.
    int   height;  //!< The height of the map pointed to by squares.
} ;

Reason :

if typedef struct{...}  B; 

so

B == struct B{...}
Steve Vinoski
  • 19,847
  • 3
  • 31
  • 46
white
  • 1
  • 1