DEV Community

mikkel250
mikkel250

Posted on

Structures and pointers in C

Structures and pointers

Even if you can pass a structure as an argument to a function, passing a pointer is more efficient. The reason being, like other data structures, if a structure is passed to a function, the entire structure must be copied (remember, all C arguments are passed by value under the hood). The same is true of all other data structures. So, in general, it is best to use pointers whenever possible for efficiency's sake, since all that needs to be copied is a memory address and not the entire data structure. Using pointers with functions, is also more efficient because addresses are typically what string-handling functions are designed to work with, which makes them easier to pass them around to functions.
Another reason to use pointers is that in some older implementations of C, a structure cannot be passed as a fuction argument, but a pointer can.

The syntax to declare a pointer to a structure is much the same as for other data structures:

// declare the pointer
struct date * datePtr = NULL;

// assign the pointer to the address of a strcture variable
datePtr = &todaysDate;

// use dereferencing to access any member of the date structure declared by datePtr
(*datePtr).day = 21;
// the parentheses above are required because the dot notation has higher precedence than
// the indirection operator (asterisk). This ensures that the dereferencing takes place
// before the assignment, otherwise it would try to access date with a null pointer
Enter fullscreen mode Exit fullscreen mode

However, C has a special operator for structures pointers, ->, the dash and greater than symbols together, which makes it much easier to dereference structures and access the variables within:

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

// declaring a struct outside of any function allows it to be used
// by any subsequent function, like a global variable

struct date
{
  int month;
  int day;
  int year;
};

int main (void)
{
  // create an instance of the structure called name, and the pointer variable
  struct date today, *datePtr;

  // immediately assign the pointer to point to the structure address
  datePtr = &today;

  datePtr->month = 8;
  datePtr->day = 25;
  datePtr->year = 2018;

  printf("Today's date is %i/%i/%i \n", datePtr->month, datePtr->day, datePtr->year);

  return 0;
};
Enter fullscreen mode Exit fullscreen mode

Structures containing pointers

A pointer can also be a member of a structure


// declare a structure type intPtrs
struct intPtrs
{
  int *pointer1;
  int *pointer2;
};

// create an instance of intPtrs called myPointers
struct intPtrs myPointers;

// declare two int variables to store inside myPointers
int int1 = 100, int2;

myPointers.pointer1 = &int1;
myPointers.pointer2 = &int2;

// dereference the pointer and assign the value to int2
*myPointers.pointer2 = 97;

printf("int1: %i, *myPointers.pointer1: %i \n", int1, *myPointers.pointer1);

printf("int2: %i, *myPointers.pointer2: %i \n", int2, *myPointers.pointer2);
Enter fullscreen mode Exit fullscreen mode

Because the above uses integers (with a known, fixed size), dynamic memory allocation is not necessary. If strings were used, then memory allocation would be used, because structures do not allocate space to store strings.

Character arrays or character pointers?

Both of the below are valid ways to declare structures, and while there are advantages to using pointers, it is important to understand how they work with structures.

struct names
{
  char firstName[20];
  char lastName[20];
}

// or

struct pnames
{
  char *first;
  char *last;
}

Enter fullscreen mode Exit fullscreen mode

To understand the difference, see the two examples below.

// create and initialize an instance of names struct
struct names veep = {"Jane", "Doe"};
Enter fullscreen mode Exit fullscreen mode

Above, the strings are stored inside the structure.
The structure has allocated 40 bytes total to hold the names.

// create and initialize an instance of the pnames struct, which contains pointers
struct pnames treas = {"Joe", "Blow"};
Enter fullscreen mode Exit fullscreen mode

Above, the strings are stored wherever the compiler stores string constants.
The structure holds only the two addresses, which takes a total of 16 bytes on the example PC, so that is all that is allocated.
The structure pnames allocates no space to store strings.
It can only be used with strings that have had space allocated for them elsewhere, such as string constants or string arrays.
So, when using pointers in structures, the pointers inside should only be used to manage strings that were created and allocated elsewhere in the program.

Whenever you have pointers inside a structure, you have to use malloc() or calloc(), otherwise they will be stored wherever string constants are stored.
Use a pointer to store the address, and use a memory allocation function to allocate just the amount of memory needed for a string.

The example below shows how to allocate memory for pointers inside structures. It uses s_gets() to read in the user input, which is similar to scanf, but it will take all user input until it hits a carriage return or end-of-file character.


// declare a structure called name, that holds pointers
struct name
{
  // using pointers instead of  character arrays (j.e. strings)
  char * firstName;
  char * lastName;
};

// hardcode the length of the character array so it can be passed in as a variable
const int SLEN = 50;

// declare a function getInfo that takes a pointer, and an instance
// of the structure declared in the previous example is passed in as an argument
void getInfo (struct name * pointerToNameStruct)
{
  char temp[SLEN];
  printf("Please enter your first name: ");
  s_gets(temp, SLEN);

  //allocate memory to hold name
  pointerToNameStruct->firstName = (char *) malloc(strlen(temp) + 1);

  //copy the name to allocated memory
  strcpy(pointerToNameStruct->firstName, temp);

  printf("Please enter your last name: ");
  s_gets(temp, SLEN);

  pointerToNameStruct->lastName = (char *) malloc(strlen(temp) + 1);
  strcpy(pointerToNameStruct->lastName, temp);

}
Enter fullscreen mode Exit fullscreen mode

In the above, the two strings are not stored in the pointerNameStruct structure itself, just the addresses. They are stored in the block of memory that is assigned and managed by malloc(). The strings are read in by s_gets, assigned to a temporary variable with a hardcoded size, and then the only the amount of required memory is allocated malloc() based on the length, which is determined by slen.

Recap

This subject is pretty complex, but to recap:

  • Structures that contain pointers do not allocate memory to store the data that is pointed to by its members, only the memory to store the addresses.
  • If the pointers are of an unknown size (typically strings), then it is possible to use the structure itself to work with the data. To do so, use:
    • a temporary variable to hold the values,
    • dereferencing with the -> symbols to access the member of the structure to work with,
    • strlen() to determine size,
    • a memory allocation function, e.g. malloc() to assign the amount of memory required, and put it in the right place in memory,
    • and strcpy() to copy the value from the temporary variable to the address pointed to by structure member.

Top comments (0)