简体   繁体   中英

having some confusion about c pointer assignment

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: %s\n", message);
  }

  exit(1);
}

void Address_print(struct Address *addr) {
  printf("%d %s %s\n", 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");
  }

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM