Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are *curr and curr->val the same value?

Consider:

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

struct node {
    int val;
    struct node *next;
};

typedef struct node item;

void main() {
    item * curr, *head;
    int i;

    head = NULL;
    for (i = 1; i <= 10; i++) {
        curr = (item *)malloc(sizeof(item));

        curr->val = i;
        curr->next = head;
        head = curr;
    }

   curr = head;
   while (curr) {
        printf("%d\n", curr->val);
        printf("%d\n", *curr);
        curr = curr->next;
   }

   getchar();
}

As I print out, *curr and curr->val are the same. Why?

I am confused about *curr. I think *curr is the value &curr points to. (I am newbie in C.)

like image 636
vancake Avatar asked Jun 29 '16 05:06

vancake


People also ask

What is curr in C?

In C, the address of a struct can be cast to an address to its first element. So (void *) &curr is the same as (void *) &(curr->val) . Here I cast everything to void * to make sure to have compatible pointer types. That means that *((int *) curr) is a perfectly defined C expression and its value is indeed curr->val .

What is a node in C?

A "node" is a concept from graph theory. A graph consists of nodes (vertices) and edges that connect the nodes. A node in C can be represented as a structure (a struct ) that has all the necessary data elements "on board" to implement a graph. Optionally a structure may be required that represents the edges.


1 Answers

First as a beginner, you should try to write correct code that raises no warning before trying to understand what happens under the hood and why some incorrect expressions still give correct results.

C is a very permissive language, that is as long as the compiler can translate what it reads it generally assumes that the programmer knows why he wrote it. It's what happens here.

In C, the address of a struct can be cast to an address to its first element. So (void *) &curr is the same as (void *) &(curr->val). Here I cast everything to void * to make sure to have compatible pointer types.

That means that *((int *) curr) is a perfectly defined C expression and its value is indeed curr->val. But it is correct, because I wrote an explicit pointer cast.

What you wrote works only by accident, because as curr is an aggregate type; you pass an int and an item * to printf and use only its first value - this is no longer standard C and I can only assume a classic implementation to guess that. But just replace your print commands by that:

printf("%d - %d\n", curr->val, 12);
printf("%d - %d\n", *curr, 15);

You should see garbage in the second printf, because with %d you declare that you pass a simple int and actually pass an aggregate. Here again, nothing is explicitly mandated per standard, but common implementation should give this result.

TL;DR: As *curr is not an int, printf("%d\n", *curr); is Undefined Behaviour. This means that anything can happen, even the expected result, but a different version of same compiler, or another compiler, or even a change in compilation parameters could give a different result, as could a minor change in the code.

And C allows automatic pointer cast to and from void * and you should never cast the return value of malloc as it can hide bugs. Please write:

curr = malloc(sizeof(item));

It is no longer C++ compatible, but is it correct C.

like image 199
Serge Ballesta Avatar answered Sep 22 '22 03:09

Serge Ballesta