1

I have the following data type:

typedef struct {
    int num;
    char *str;
} NumStr;

And the variable x:

NumStr *x;

How can I allocate heap space for the str pointer? I've tried

x->str = (char*)malloc(sizeof(char*));

But it isn't working.

Im pretty new to C, so I apologize if I am missing something obvious. Thanks in advance.

4 Answers4

4

A pointer like NumStr* points to somewhere in memory - and so you need to allocate x before you assign to x->str:

NumStr* x = malloc(sizeof(*x));.


Note that there is no need to cast to (char*) as you've done - and don't forget to free(x->str); and then free(x); in that specific order.

Daniel Kleinstein
  • 5,262
  • 1
  • 22
  • 39
  • To be more precise, no specific order of allocation is required. However, both must be done before the assignment to `x->str`. – CiaPan Aug 30 '21 at 19:12
0

You could simply do

NumStr x;
x.int = 3;//for example
x.str = malloc(5*sizeof(char));

If you would ever need pointer to x (pretty much equivalent to x in your code) later, just use &x.

Explanation of my code:

The x gets automatically allocated on the stack, just as int would do (as in int x; x = 0;). You can initialize it freely afterwards (as in my example above). NumStr *x declaration allocates variable of type NumStr *, pointer, that you typically initialize with malloc (as in Daniel's answer), and only then you initialize the allocated memory.

(As always when using -allocs) You need to free the memory pointed to by it later, yourself.

To clarify one more thing: x->str = (char*)malloc(sizeof(char*)); should be corrected to x->str = malloc(sizeof(char));, optionally x->str = malloc(5*sizeof(char)) or something.

wojand
  • 158
  • 9
0

As far as your actual question:

How can I allocate heap space for the str pointer?

What you've done (x->str = (char*)malloc(sizeof(char*));) probably isn't what you want. sizeof(char*) is most likely 4 or 8 depending on your system, but more importantly is unrelated to the char object(s) that x->str will point to. When allocating dynamic memory, the general paradigm is to allocate space for the type "one level up" from the lvalue you're assigning to, as a combination of the sizeof that type and the amount of space desired. That is, for some type T, you want to allocate space in the following manner:

// pseudo code
T* myPointerToT = malloc(sizeof(T) * numberOfTObjectsIWant);

Here, myPointerToT is a T pointer type (T*). "One level up" is a type T, and so this is what you want to feed to sizeof. A T* type should point to T objects, so you must allocate enough size for the number of T objects you need.

One more thing, rather than using T in sizeof(T), the preferred syntax is to use the dereferenced variable name. In the example above, that would be *myPointerToT, changing the line to:

T* myPointerToT = malloc(sizeof(*myPointerToT) * numberOfTObjectsIWant);

The reason for this less maintenance down the road. Imagine T is a char, and sometime later, this changes to int. We now have to change T in two places:

char* myPointerToT = malloc(sizeof(char) * numberOfTObjectsIWant);

changes to

int* myPointerToT = malloc(sizeof(int) * numberOfTObjectsIWant);

whereas if we started with

char* myPointerToT = malloc(sizeof(*myPointerToT) * numberOfTObjectsIWant);

we now only have to change T in one place:

int* myPointerToT = malloc(sizeof(*myPointerToT) * numberOfTObjectsIWant);

Note, sizeof is a compile-time operator, so *myPointerToT isn't really dereferencing anything; the preprocessor can look at that and determine the type, which is what sizeof needs.

In your case, x->str is a char* type, so you want to allocate space for at least a single char object.

// as stated in another answer, no need to cast malloc return value
x->str = malloc(sizeof(char));
// or
x->str = malloc(sizeof(*(x->str)));

In practice, allocating space for a single char is foolish, and as indicated by your variable name, this is meant to be a string, so you'll want multiple chars:

x->str = malloc(sizeof(char) * numOfCharsIWant);

Furthermore, the C standard defines sizeof(char) to be 1, so this can be omitted as well:

x->str = malloc(numOfCharsIWant);

Finally, you should only dynamically allocate memory if you "have" to, which in practice usually boils down to:

  1. You won't know how much memory you'll need until runtime
  2. You need "a lot" of memory. What "a lot" means depends on your system, but in my experience the default stack size for each execution thread on desktop linux is 8MB, which is plenty of space for usual operations.

If you have a general idea what your max string size will be, you could bypass the dynamic memory allocation all together do something like the following:

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

#define MAX_STR_LENGTH 30  // "small enough"

typedef struct {
    int num;
    char str[MAX_STR_LENGTH];
} NumStr;

int main(void)
{
  // a single object, keep it in automatic storage
  NumStr x;

  x.num = 3;
  strcpy(x.str, "hello")

  printf("%d: %s\n", x.num, x.str);

  // no need to clean up dynamically allocated memory, since there is none
  return 0;
}
yano
  • 4,827
  • 2
  • 23
  • 35
0

You used

x->str = (char*)malloc(sizeof(char*));

but the sizeof operator will give you the size of the poiinter type itself (which is not what you want, as the pointer is already allocated space in the structure). If you want to allocate space for a string of, let's say, 50 characters, you should use

x->str = malloc(50);  /* don't use a cast to convert the pointer type,
                       * malloc already solves that, giving you a 
                       * compatible pointer type. */

And you should use it as if the pointer was a pointer to an array of 50 chars (char [50]).

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31