0

I created a structure for a linked list node in C as follows.

struct node
{
    int data;
    struct node *next;
} *START = NULL;

Then when I need to access the properties of the structure, I create a pointer to structure as follows.

struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;

I want to know if we can use

struct node node1

instead of the current declaration and what changes would that make in the program.

Also, I want to know why *START=NULL is outside the structure and what its data type is ?

aep
  • 1,393
  • 9
  • 18
Nacho Libre
  • 326
  • 4
  • 14

4 Answers4

2

You need to allocate the memory for the struct. Here you have a simple function which appends the node to the end of the list


struct node
{
    int data;
    struct node *next;
} *START = NULL;

struct node *append(int data)
{
    struct node *node1 = malloc(sizeof(*node1));
    struct node *list = START;
    if(node1)
    {
        node1 -> data = data;
        node1 -> next = NULL;
        if(list)
        {
            while(list -> next)
            {
                list = list -> next;
            }
            list -> next = node1;
        }
        else
        {
            START = node1;
        }
    }
    return node1;
}

START is the variable of type pointer to the struct node.

0___________
  • 34,740
  • 4
  • 19
  • 48
1
struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;

First, the above code doesn't initialize node1 to a valid memory address. It merely creates a pointer called node1 which can take the address of a variable of struct node type which hasn't been properly initialized.

You need to change the code to the following.

struct node *node1 = (struct node*)malloc(sizeof(struct node));
node1 -> data = 12;
node1 -> next = NULL;

The above will allocate memory for struct node type and initialize node1 with the address of the allocated memory.

Now let's get to your questions.

I want to know if we can use

struct node node1

instead of the current declaration and what changes would that make in the program.

You can use the above declaration in your program, but it will create node1 on stack rather than on heap. Probably this is not the behaviour you want since the variable made on stack has the lifetime of the scope in which it's created. In your case I assume you want to create a linked list (or similar structure), therefore you need the list to be accessible even after the function in which the appending happens returns.

Anyway, if you created the variable on stack you can simply use . operator to access structure members.

struct node node1;
node1.data = 12;
node1.next = NULL;

Also, I want to know why *START=NULL is outside the structure and what its data type is?

It simply defines a pointer variable named START that can point to struct node and initialize it with NULL.

aep
  • 1,393
  • 9
  • 18
  • Three issues in two lines of code: 1. casting the result of malloc is considered as bad practice. 2. Not checking the result of the malloc is a serious error. 2. Using types instead of objects in the sizeif is considered as a bad practice. – 0___________ Jul 19 '20 at 12:03
  • @P__J__ I was answering the questions and to the point. Please double check the questions. And I don't understand what you mean by `using types instead of objects in the sizeof() is a bad practice` ? It is not. – aep Jul 19 '20 at 12:06
  • 1
    `struct node *node1 = malloc(sizeof(struct node));` should be `struct node *node1 = malloc(sizeof(*node1));` Why? If you have many similar sizeof-s in your code and you change the type of the `node1` your code will be erratic. Using types is error prone. It was discussed here many times - search for more detailed explanation. – 0___________ Jul 19 '20 at 12:10
  • I wish if you can point me to a reliable source. But your comment is merely regarding a `typo` that a user can make. Similarly user might drop `*` and allocate sizeof a pointer if they follow the pattern you suggest i.e. `malloc(sizeof(node1))` instead of `malloc(sizeof(*node1))`. – aep Jul 19 '20 at 12:14
  • 1
    When you spend one day a week chasing the hard to spot error caused by your approach - you will change your mind. – 0___________ Jul 19 '20 at 12:27
  • 1
    @P__J__ I think your comment is subjective rather than being a good practice or not in general. BTW, nice to know a different view. – aep Jul 19 '20 at 12:35
  • 1
    @P__J__ I would indeed not downvote a question because of that. It is just a matter of coding-style. Both versions are correct, although the "type of pointer" version is more safe, indeed. – RobertS supports Monica Cellio Jul 19 '20 at 12:44
  • @aep, P__J__'s remark about use of `sizeof` to determine allocation sizes is *absolutely* describing a matter of best practices. As he says, that convention is widely recommended around here, by many of the regulars. Also as they say, it both reduces the likelihood of errors and makes your code more resilient to modifications. That doesn't make the alternative *wrong*, of course, but if you choose to be in the business of making coding recommendations then you should be prepared for your recommendations to be evaluated against a higher standard than "not wrong". – John Bollinger Jul 19 '20 at 12:57
  • @JohnBollinger To me the question was not regarding the best practice to specify `size` when using `malloc` and I was simply interested to get P__J__'s opinion on his view. As you can clearly see, I wasn't trying to sell my alternative here. I personally reckon that P__J__'s comment was heavily focussed on a part of the answer which is not pertaining to the real question. – aep Jul 19 '20 at 13:06
1

When do we use structure variable and structure pointer?

Depends on the use case. When you create a structure variable you actually allocate the structure object on the stack. When you use pointer you usally allocate the structure object in heap memory and point to this object via the pointer.

You can resize and deallocate the dynamically allocated structure object whenever you want to, while the static can't be changes in size and it is only destroyed once the scope of it ends (in case of an automatic structure variable).

More details to the difference between static vs. dynamic allocation you can find in the links below the answer.

Which way you choose, depends on what you want to do and how you want to do it.

I want to know if we can use struct node node1 instead of the current declaration and what changes would that make in the program.

That would make node1 a variable of the structure itself; it would not be a pointer to an object of the structure only anymore.

Beside the things mentioned above and others, the access to the members would be different:

node1 . data = 12;
node1 . next = NULL;

Also I want to know why *START=NULL is outside the structure and what it's data type is.

START is of type struct node * (a pointer to struct node) and initialized to NULL. It's definition is outside because it isn't a member, it is a pointer to an object of the structure.


Note that you need to assign a pointer to struct node to point to an object of struct node, but that is not what you did at:

struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;

So, this would invoke undefined behavior.

Allocate memory for the structure:

struct node *node1 = calloc (1, sizeof(*node1));
if (!node1)
{
    fputs("Failure at memory allocation for node1!", stderr);
    return EXIT_FAILURE;
}
node1 -> data = 12;
node1 -> next = NULL;

Related regarding point 1.:

  • Structure *vs* pointer-to-structure is not necessarily a question of stack *vs*. heap. – John Bollinger Jul 19 '20 at 13:00
  • @JohnBollinger Yes, you are right. But IMHO a pointer to structure is way more often used with allocating dynamic memory than to just point static allocated structures. – RobertS supports Monica Cellio Jul 19 '20 at 13:18
  • I don't disagree, but that's irrelevant. The parts of this answer about stack and heap are not responsive to the question the OP actually posed, and given the OP's apparent level of C experience, I account those parts more likely to muddy the issue than to be helpful. – John Bollinger Jul 19 '20 at 14:12
  • @JohnBollinger OP's question is "*When do we use structure variable and structure pointer?*" - One *main* difference in the intentional use is the concern where to store, or more precise static vs. dynamic allocation and thus to explain stack and heap would makes sense. – RobertS supports Monica Cellio Jul 19 '20 at 14:20
  • @JohnBollinger Given that, what would you change in particular? Removing the links or to mention stack and heap in general? – RobertS supports Monica Cellio Jul 19 '20 at 14:20
  • The question isn't even directly about static *vs* automatic *vs* allocated storage duration, though **that** does factor into a good answer. Yes, I would eliminate all discussion of stack and heap, which aren't C concepts in the first place. The question is about syntax and semantics of structures, structure pointers, and their declarations, and that is already plenty to talk about without overloading or districting the OP. – John Bollinger Jul 19 '20 at 14:28
1

[...] when I need to access the properties of the structure, I create a pointer to structure as follows.

struct node *node1;
node1 -> data = 12;
node1 -> next = NULL;

Not exactly. You have declared node1 as a variable of type struct node *, but you have not created a pointer, in the sense that you have not given that variable a value that points to any structure. Subsequently attempting to access a struct node via that variable's (indeterminate) value therefore produces undefined behavior. Among the more likely outcomes are that your program crashes or that unexpected changes are made to random objects in its memory.

To be able to use node1 to access a struct node as you show, you first need to assign it to point to one (or at least to memory that can be made to contain one). You can do that either by assigning it the address of an existing struct node or by allocating memory sufficient for a struct node and assigning its address to node1. More on those alternatives later.

I want to know if we can use

struct node node1

instead of the current declaration and what changes would that make in the program.

You definitely can declare node1 as a struct node instead of as a pointer to one. In the scope of such a declaration, you would access its members via the direct member-access operator (.) instead of via the indirect one (->):

node1.data = 12;
node1.next = NULL;

Furthermore, one of the ways to obtain a pointer to a struct node would be to use the address-of operator (&) to obtain that structure's address:

struct node *node_ptr = &node1;

HOWEVER, the lifetime of the node1 object declared that way ends when control passes out of the innermost block in which the declaration appears (if any), any pointers to it notwithstanding. As such, that usually is not what you want for a linked-list node.

For linked-list applications (among others), one generally wants an object whose lifetime doesn't end until you say it should do, and that can be achieved by dynamically allocating memory for the structure. For example,

struct node *node_ptr = malloc(sizeof(*node_ptr));

The allocated memory remains allocated until you explicitly free() it, whether in that scope or in another. Either way, to access the structure members through a valid pointer, one uses the indirect access operator, as in your example:

node_ptr->data = 42;
node_ptr->next = NULL;

or, equivalently, one first dereferences the pointer and then uses the direct member access operator:

(*node_ptr).data = 42;
(*node_ptr).next = NULL;

.

Also, I want to know why *START=NULL is outside the structure and what its data type is ?

You said that you wrote the code. If you don't know the significance of the *START=NULL part, then what is it doing in your code?

In any event, it is analogous to the *node_ptr = &node1 above. START is declared (at file scope) as a pointer to a struct node, and its initial (pointer) value is assigned to be NULL, which explicitly and testably does not point to any structure.

John Bollinger
  • 121,924
  • 8
  • 64
  • 118