简体   繁体   中英

How to use Malloc pointers in comparison to array in C

I created a struct called PLAYER and I want to create an list that stores the pointers to the PLAYER object.

If I want to accomplish it with

PLAYER **ptr = malloc(10*sizeof(PLAYER *));

How can I assign the pointers to each index? I tried:

PLAYER *a;
PLAYER *b;
ptr[0] = a;
ptr[1] = b;

1.This seems to work. Can I get some explanation on the memory address behind it?
I also tried:

ptr = a;
//increase the address and assign b
ptr += sizeof(PLAYER *);
ptr = b;

2.This does not work correctly I think. Can I see a correct way of assign the list without using the [] brackets?

3.If I allocate only one entry's size and assign multiple ones:

PLAYER **ptr = malloc(1*sizeof(PLAYER *));
ptr[0] = a;
ptr[1] = b;

I can get these PLAYER object by using ptr[0] ptr[1], but will this cause any problems like overwrite other memories?

4.If I use [] brackets, do I need to malloc at each index in order to use it?

PLAYER *ptr[10];
for(int i = 0; i < 10; i++)
  ptr[i] = malloc(sizeof(PLAYER *));

5.Do I need to free an array after using it? such as:

char ptr[10] = "abc";
//do something with ptr
free(ptr);
char *ptr2[10] = {"123", "abc"};
free(ptr2);

Any help would be much appreciated!

If you have a PLAYER **ptr = malloc(10*sizeof(PLAYER *));
That means you have to malloc for every ptr[i] = malloc(sizeof(PLAYER));

Accessing the array at indexes would be ptr[i]->somevalue

NOTE: if you have pointers inside the struct you need to allocate for those as well!!

Freeing your memory would be:

for(int i = 0; i<10;i++){
    free(ptr[i]->anyAllocatedPointersInside);
    free(ptr[i]);
}
free(ptr);

SPECIFICALLY IN THAT ORDER

If you update the post with the full struct I can update mine to more accurately help you.

When in doubt, think of malloc() allocations in these terms: it allocates raw memory, and it doesn't know anything about your structs, When you think in these terms. you'll get it right.

Let's try to answer to your questions:

  1. You are basically instancing within the stack a pointer, with any content into it, just as int hello; . That integer can contain anything, because you don't set it as in int hello = 2; . The same thing is happening with your pointers: int * hello; will be a pointer (to an integer) that can contain any address. Hence, if you dereference a pointer like that, your chances to get caught into SIGSEGV are not low. Then, once you have created those pointers that can be anything, you're assigning their address to the pointer of pointers array you've allocated. Don't do that.

  2. That doesn't work correctly, because if you have an array of pointers to a given type, you can simply increment with += n , the compiler will calculate the appropriate "sizeof(type_you're-pointing_to)" and will add that automatically. This is the main purpose of declaring a pointer to a given type.

  3. You're effectively overwriting other memory.

  4. Brackets are just pointer dereferencing: *ptr+n same as ptr[n] .

  5. You need to free each line, and then the array of pointers of pointers. Basically every pointer you get with malloc() , you have to free it with free() . DO NOT call free() to any other pointers that hasn't been spit out from malloc() .

Let me show you some code I have just written to show you better:

#include <stdlib.h>
#include <stdio.h>
#include <string.h> // for memset

#define N_POINTERS 4
#define M_PLAYERS_PER_LINE 3


struct PLAYER
{
  int id;
  int score;
  int age;
};


int
main()
{
  // Allocate the array of pointers, big enough to old N pointers.
  struct PLAYER ** pointers = malloc(N_POINTERS*sizeof(struct PLAYER*));
  // Always better zeroize pointers arrays.
  memset(pointers, 0, N_POINTERS*sizeof(struct PLAYER *));
  // Allocate each line of M `PLAYER` structs.
  // Basically we allocate N chunks of memory big enough to contain M PLAYER structs one next each other.
  // What we get is something like this:
  //
  // pointer      pointers              PLAYER lines
  // of pointers   array
  //   [addrP] -> [addr0] -> [PLAYER0 PLAYER1 PLAYER2] .. M
  //              [addr1] -> [PLAYER0 PLAYER1 PLAYER2] .. M
  //               ...N
  //
  int id = 0;
  for (int i = 0; i < N_POINTERS; ++i)
  {
    pointers[i] = malloc(M_PLAYERS_PER_LINE*sizeof(struct PLAYER));
    // Set the data you want to the structs.
    for (int k = 0; k < M_PLAYERS_PER_LINE; ++k)
    {
      pointers[i][k].id = id++;
      pointers[i][k].score = 123 + k;
      pointers[i][k].age = 33 + i;
    }
  }

  // Print data.
  // Here we use a single PLAYER pointer that will
  // traverse the entire PLAYER matrix.
  struct PLAYER * player;
  for (int i = 0; i < N_POINTERS; ++i)
  {
    for (int k = 0; k < M_PLAYERS_PER_LINE; ++k)
    {
      // Assign the current PLAYER to our pointer.
      player = pointers[i] + k;
      // Print PLAYER data, by reading the pointed struct.
      printf("Player: #%i  age:%i  score:%d\n", player->id, player->age, player->score);
    }
  }

  // Deallocate!
  for (int i = 0; i < N_POINTERS; ++i)
  {
    // Deallocate each line chunk.
    free(pointers[i]);
  }
  // Deallocate the array of pointers.
  free(pointers);
  return 0;
}

As a bonus track, if you need to allocate a matrix of M*N PLAYER structs, you should also look at this code, that will allocate M*N PLAYER structs into one unique memory block, one next each other, which is much more easier to manage, as you can see by the code itself:

#include <stdlib.h>
#include <stdio.h>

#define LINES 4
#define COLUMNS 3
#define GET_ARRAY_POS(lin, col) (col+(lin*COLUMNS))

struct PLAYER
{
  int id;
  int score;
  int age;
};


int
main()
{
  // Allocate a *FLAT* array of PLAYER structs, big enough to
  // contain N*M PLAYER structs, one next each other.
  struct PLAYER * array = malloc(LINES*COLUMNS*sizeof(struct PLAYER));

  // Set the data you want to the structs.
  int id = 0;
  for (int lin = 0; lin < LINES; ++lin)
  {
    for (int col = 0; col < COLUMNS; ++col)
    {
      int pos = GET_ARRAY_POS(lin, col);
      array[pos].id = id++;
      array[pos].score = 123 + col;
      array[pos].age = 33 + lin;
    }
  }

  // Print data.
  // Here we use a single PLAYER pointer that will
  // traverse the entire PLAYER matrix.
  for (int i = 0; i < (LINES*COLUMNS); ++i)
  {
    // Print PLAYER data, by reading the pointed struct.
    printf("Player: #%i  age:%i  score:%d\n", array[i].id, array[i].age, array[i].score);
  }

  // Deallocate!
  free(array);
  return 0;
}

Enjoy! ^_^

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