Home > Blockchain >  Is it necessary to declare the datatype for a Double Pointer (a Pointer to a Pointer) if we are sure
Is it necessary to declare the datatype for a Double Pointer (a Pointer to a Pointer) if we are sure

Time:06-08

I was studying linked lists, and I had this question: Why would we need to declare the datatype for a double pointer? I think that, if you dereference such pointer (say dptr (a pointer to a pointer) ), you'd get a pointer to insert_datatype. Now if I were to just change this value, that is just changing where the dptr points to. And hence when I dereference this double pointer twice, I would still be dereferencing a structure (in my below code). So is it really necessary to declare the datatype for double pointers if we are using them to only dereference once? I can see why we would need to know the datatype while dereferencing the dptr twice, as *dptr would give us a pointer to insert_datatype, and when I do **dptr, it would be needed to know what is the datatype *dptr is pointing to.

#include "stdio.h"
#include "stdlib.h"
typedef struct Node{
    int data;
    struct Node* next;
}Node;

void addAtBeg(int**, int);

int main(){
    int a;
    Node* head=NULL;
    printf("Enter data:\n");
    scanf("%d",&a);
    addAtBeg(&head,a);
    printf("%#x\n",head);
    printf("%d\n",(*head).data);
    return 0;
}

void addAtBeg(int** head, int a){
    Node* p;
    p=(Node *) malloc(sizeof(Node));
    p->data=a;
    p->next=*head;
    *head=p;
}

I also can seem to just declare a long long int* head as the parameter receiving the &head in the addAtBeg, and it just works fine, as *head=p would just fetch 8 bytes, and write the memory address at that location.

So, are these both behaviors UB or are valid syntaxes?

CodePudding user response:

Pointers to different types don't necessarily have the same representation. On most systems you're likely to come across this will be the case, but it's not true in general.

While it is legal to convert an object pointer of one type to an object pointer to another type and back, it is not allowed to dereference the converted pointer except in a few cases which don't apply here.

So this:

*head=p;

Triggers undefined behavior.

CodePudding user response:

Using either int** head or long long int* head in addAtBeg's prototype is undefined behavior (specifically, the moment you do *head = p;, assigning a Node* to something that is thought to be a non-Node*). long long int* head is worse, in that it's far more likely to trigger a size mismatch (e.g. on 32 bit systems, the Node* you're dereferencing to will typically be 32 bits, while long long int is 64 bits, so the assignment would overwrite four bytes from neighboring value(s) on the stack). Both will probably work just fine (assuming you disable/ignore all warnings) up until the point where it turns out sizeof(long long int) != sizeof(Node*) or (less commonly) sizeof(int*) != sizeof(Node*).

The real question is why you would do this? You still need to pass &head (that's unavoidable, head needs to be reassigned by the callee). There's no performance benefit. Since you're passing by pointer, you don't need the definition of Node, just a forward declaration if the declaration/definition isn't in that file. The function is replacing the pointer entirely, and is clearly aware it's working with a Node, so no information hiding or implementation details are being hidden from anyone. So what are you getting out of violating the type system?

  • Related