2
votes

Recently this question was asked on stack overflow , but I have different doubt regarding memory allocation.

In this line Graph *G=malloc(sizeof(*G)) here memory allocation is for pointer to Graph and and if you want to say that memory allocation for other member of struct is not happening inside any struct then how we are able to access them using G->var, since we are allocating memory for only (*G) which may be equal to some int value?

If you say:

It is allocating a Graph structure and assigning G to the address of that structure

than Graph *g = malloc( sizeof( Graph ) ); will also do the same.

struct Edge {
    int vertex;
    int weight;
    Edge *next;
};

struct Graph {
    int v;
    Edge **edge;
    int *dist;
    int *path;
};

Graph *graph_new(int v)
{
    Graph *G = malloc(sizeof(*G));

    G->v = v;
    G->edge = calloc(v, sizeof(*G->edge));
    G->dist = calloc(v, sizeof(*G->dist));
    G->path = calloc(v, sizeof(*G->path));

    return G;
}
2
What exactly are you asking? - merlyn
Without the first malloc, you can't even access G -> anything. It creates the variables inside the struct. Without that, G is just a pointer pointing to nowhere. - Spikatrix
Edge *next; Edge is not a defined type. In C, this should be a syntax error. - wildplasser

2 Answers

0
votes

...how we are able to access them using G->var...

It seems you don't understand clearly what a pointer is. A pointer is a simple variable you can read and write as any other. But you can do one more operation on a pointer: dereference it (using * or ->). In order to do this particular operation, the value of the pointer must be valid: a pointer contains an address and, if that address is not valid, an error happens. Think at a pointer as an envelope, written or not. You can read what is written ON the envelope; you can also wipe and write on it. But when you read the address written on the envelope, you want that address exists, otherwise you could go around searching an address which does not exist, and get angry.

The particular value of a pointer can be thought similar to that of an integer. You can take any integer and perform calculations with it but, if you want to divide for it, your integer must be different from 0, otherwise an error happens. So is a pointer: you can read it and write it with any value but, if you want to use its value as what should normally be, i.e. an address in memory, that value must point to a suitable address. malloc() and calloc() return values which are valid and suitable to be assigned to a pointer, and can be safely used (in normal circustances) when you try to dereference the pointer.

EDIT after comments below. One normally thinks that, if a program is not guaranteed to behave correctly, it is an error. For the program to always behave correctly, many precautions must be taken. Two of these are 1) Don't use unknown values, and 2) Don't dereference invalid pointers. Errors can be divided finely further, by nomenclature, style, or the effect they produce or can produce. Undefined behavior is the name given by the C language specification to indicate that the compiler (or the target machine) can do whatever they want, because the specification does not mandate anything precise about. Of course, nobody wants "undefined behavior", so making it happen is just an error. And back to dereferencing wrong pointers, the specification says it invokes undefined behavior. Precisely, depending on the target machine and OS, one or more of the following can happen: 1) nothing, apart from reading unknown values; 2) nothing, apart from writing to unknown memory zones; 3) segment faults or other traps/exceptions and so on; 4) CPU overheating, maybe explosion, or other unspecified things.

Now we take a step ahead. If your pointer variable is not a "normal", global variable, but instead resides in dynamic - non allocated - memory, your variable does not exist yet. It is a concept, not a real variable. So, first you create that variable; then you can use it as said before.

In your example, "Struct Graph" is a declaration of a bunch of variables which do not exist until you allocate them. Once you do it, via "Graph *G = malloc(sizeof(*G));", they come to life; but this does not mean they have valid values. In fact, just below creating the struct, in you code fragment, they are accessed. The only legal access to them, in this moment, is to assign them some value. As said before, they could also be read - they actually exist, but their value could (well, IS) illegal.

If the values in the Struct Graph, just created, were simple integers instead of pointers, the matter would be the same: the variables exist, but their content is unknown and hence invalid. Note that you could allocate a Struct Graph using calloc(): in this case the value of the variables inside would not be unknown but, for a pointer, still would be invalid to be dereferenced - like an integer known to be zero and hence invalid to be used as a divisor. But the variables ARE there, ready to be tested against 0 (in case of an integer), or against NULL (or 0) in the case of pointers, or ready to be written with meaningful values.

Hope I've been clear enough to help.

0
votes

Graph *G=malloc(sizeof(G)) != Graph *G=malloc(sizeof(*G))

G is a pointer to Graph hence sizeof(G) in the first case allocate memory for Graph *.

While sizeof(*G) in the second case allocates enough memory for what G points to, which in this case is Graph.

How you choose to allocate memory is entirely up to you and depends on what you intend to do.

Secondly, If you have fields that are pointers in a struct as in struct Graph, those will remain unallocated, any attempt to access them will result in an error until you properly allocate memory for them or point them to valid memory locations.