TransWikia.com

having some confusion about c pointer assignment

Stack Overflow Asked by dablyputs on November 27, 2021

I’m having some trouble wrapping my head around pointer assignments in C. The asterisk character appears in many different locations and I don’t understand why I would choose to use one way over the other.

Specifically in the code below:

why would I choose:

conn->db->rows = (struct Address**)malloc(sizeof(struct Address *) * conn->db->MAX_ROWS);

over:

conn->db->rows = (struct **Address)malloc(sizeof(struct Address *) * conn->db->MAX_ROWS);

and within sizeof, what does the asterisk indicate?

This is the origin of the code above. Not the entire program.

struct Address {
  int id;
  int set;
  char *name;
  char *email;
};

struct Database {
  int MAX_DATA;
  int MAX_ROWS;
  struct Address **rows; // USE ARRAY OF POINTERS
};

struct Connection {
  FILE *file;
  struct Database *db;
};

void die(const char *message) {
  if(errno) {
    perror(message);
  } else {
    printf("ERROR: %sn", message);
  }

  exit(1);
}

void Address_print(struct Address *addr) {
  printf("%d %s %sn", addr->id, addr->name, addr->email);
}

void Database_load(struct Connection *conn) {
  size_t i=0;

  // Each database will have two `int` values. read
  // those first.
  assert(conn->db && conn->file);
  if (!(conn->db && conn->file))
      die("Database load : Invalid Connection info");
  if (fread(&conn->db->MAX_DATA, sizeof(conn->db->MAX_DATA), 1, conn->file) != 1)
      die("Database load : Couldn't read MAX_DATA");
  if (fread(&conn->db->MAX_ROWS, sizeof(conn->db->MAX_ROWS), 1, conn->file) != 1)
      die("Database load : Couldn't read MAX_ROWS");
  conn->db->rows = (struct Address**)malloc(sizeof(struct Address *) * conn->db->MAX_ROWS);

  assert(conn->db->rows);
  if (!(conn->db->rows)) {
    die("Database_load : Could not MAX_ROWS Address  structures");
  }

One Answer

struct **Address is illegal syntax. The base type is struct Address and there should be nothing but whitespace (comments count as whitespace) between the struct keyword and the tag, Address.

struct Address * is a type that is a pointer to a struct Address.

struct Address ** is a type that is a pointer to a pointer to a struct Address.


A sizeof expression determines the size of a type in bytes. There are two forms:

  • sizeof(type) (for some type, type) specifies the type directly.
  • sizeof expression (for some expression, expression) uses the resulting type of expression without evaluating expression.

In the case of sizeof(struct Address *), the first form is used. This is evaluated as the size of the struct Address * type (pointer to struct Address) in bytes.

In the statement:

conn->db->rows = (struct Address**)malloc(sizeof(struct Address *) * conn->db->MAX_ROWS);

the result of the call to malloc is a generic pointer type, void * and it is being cast to the struct Address** type by the cast operator (struct Address**) to match the type of the rows member being assigned to.

In C, it is actually the usual practice to omit the cast when assigning a void * value to something of another object pointer type, or vice versa. The statement can be rewritten, omitting the cast, as:

conn->db->rows = malloc(sizeof(struct Address *) * conn->db->MAX_ROWS);

Additionally, the type operand of sizeof(type) can be replaced with an expression that has the same type. Since conn->db->rows has type struct Address**, then *conn->db->rows or conn->db->rows[0] will have type struct Address *. Either of those could be substituted into the statement, rewriting it as, for example:

conn->db->rows = malloc(sizeof(*conn->db->rows) * conn->db->MAX_ROWS);

That can be less error-prone than specifying the type directly in the sizeof expression, and is common practice.

Answered by Ian Abbott on November 27, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP