0

I have the following code. I know that is wrong, but the thing is that I dont get why. Below I explain my doubts.

#include <stdio.h>


struct mychar {
    char value;
    struct mychar *nextPtr;
};

typedef struct mychar Mychar;


void insert(Mychar **, char );    // line 19
void printlist(Mychar **);


int main(){
    Mychar *startPtr = NULL;

    insert(&startPtr, 'b');

    printlist(&startPtr);

}


void insert(Mychar **sPtr, char myvalue){
    Mychar *newlinkPtr = calloc(1, sizeof(Mychar));

    if (**sPtr == NULL){    // if I put two ** I get errors
        newlinkPtr->value = myvalue;
        newlinkPtr->nextPtr = **sPtr;    // same here
        **sPtr = newlinkPtr;    // same here
    }
}


void printlist(Mychar **startPtr){
    printf("%c\n", *startPtr->value);    // get error
}

Here are the errors:

liste_collegate.c:29:13: error: invalid operands to binary expression ('Mychar' (aka 'struct mychar') and 'void *')
        if (**sPtr == NULL){
            ~~~~~~ ^  ~~~~
liste_collegate.c:31:23: error: assigning to 'struct mychar *' from incompatible type 'Mychar' (aka 'struct mychar'); remove *
                newlinkPtr->nextPtr = **sPtr;
                                    ^ ~~~~~~
liste_collegate.c:32:10: error: assigning to 'Mychar' (aka 'struct mychar') from incompatible type 'Mychar *' (aka 'struct mychar *'); dereference with *
                **sPtr = newlinkPtr;
                       ^ ~~~~~~~~~~
                         *
liste_collegate.c:38:26: error: member reference base type 'Mychar *' (aka 'struct mychar *') is not a structure or union
        printf("%c\n", *startPtr->value);

My doubts:

  • Why if in the arguments of insert function I write **sPtr, then in the if block I have to use *sPtr, otherwise it gives me error? Shoudn't **sPtr be equal to NULL, since I have put NULL value inside it in the main? In the main() , when I call insert in line 19, I send there the address & of startPtr, so to access to its value NULL in the insert function, I should put a * to actually reach the pointer, and another * to actually reach the NULL value..
  • In printlist function, pretty much the same doubts of before. If I "send" to printlist the address of the first pointer of the linked list, to actually access the first structure, shouldn't I dereferenciate to actually reach the struct address, and then dereferenciate again with -> to control the pointer of that structure to get "value"?
Mnkisd
  • 504
  • 2
  • 12

2 Answers2

1

First for your insert function:

void insert(Mychar **sPtr, char myvalue){
    Mychar *newlinkPtr = calloc(1, sizeof(Mychar));

    if (**sPtr == NULL){    // if I put two ** I get errors
        newlinkPtr->value = myvalue;
        newlinkPtr->nextPtr = **sPtr;    // same here
        **sPtr = newlinkPtr;    // same here
    }
}

sPtr has type Mychar **: pointer to pointer.

*sPtr has type Mychar *: pointer to type Mychar.

Now when you use **sPtr has type Mychar: a value with type Mychar.

NULL is used for pointer not for value. So if you want to compare, you can compare either sPtr with NULL or *sptr with NULL. You should not compare the value **sPtr with NULL. BTW, your function can become like:

void insert(Mychar **sPtr, char myvalue){
    Mychar *newlinkPtr = calloc(1, sizeof(Mychar));
    if (!newlinkPtr) {return;} // you should check the return value of calloc funciton because it may be failed

    if (*sPtr == NULL) {  
        newlinkPtr->value = myvalue;
        newlinkPtr->nextPtr = *sPtr;   
        *sPtr = newlinkPtr;  
    }
}

For print function:

void printlist(Mychar **startPtr){
    printf("%c\n", *startPtr->value);    // get error
}

*startPtr->value should change to (*startPtr)->value.

But, with print function, you do not need to use pointer to pointer, because in this function, you do not change or update anything. You can use pointer as:

void printlist(Mychar *startPtr){
    printf("%c\n", startPtr->value);
}

If you do that, in main function, when you call print function:

printlist(startPtr);
Hitokiri
  • 3,607
  • 1
  • 9
  • 29
  • Thanks a lot. ! One question: why in the linked lists do I need to pass the address of the pointer with `&` to `insert` function ? – Mnkisd May 23 '20 at 12:11
  • with `insert` function, instead of return HEAD pointer (it's `startPtr` in your code) we pass the argument as the pointer to HEAD pointer. For your case, In main function, you declare `Mychar *startPtr`, it means `startPtr` has type `Mychar *`, and in the declaration of `insert` function, you use pointer to pointer (the type is `Mychar**`), so you have to use `& `: `insert(&startPtr, 'b');`. You can see more info at the link https://stackoverflow.com/questions/7271647/what-is-the-reason-for-using-a-double-pointer-when-adding-a-node-in-a-linked-lis – Hitokiri May 23 '20 at 12:27
0

"Shoudn't **sPtr be equal to NULL, since I have put NULL value inside it in the main?"

No.

NULL is a macro for a null pointer; It is used for pointers only, not it´s referenced objects (unless the referenced object is also a pointer and you want to check if for NULL, but that´s not the point here).

**sPtr is a pointer to pointer to type Mychar, actually a struct. If you dereference sPtr ( means *sPtr) you access the pointer it is pointing to (actually startPtr in main), which is correct for checking NULL.

If you use if (**sPtr == NULL) you attempt to dereference startPtr - a NULL pointer - itself, which is invalid and attempt to check the object startPtr is pointing to (actually nothing) for NULL, but not startPtr.

"Shouldn't I dereferenciate to actually reach the struct address, and then dereference again with -> to control the pointer of that structure to get "value"?"

You need to dereference the pointer to pointer startPtr first and thereafter access value by ->. Use (*startPtr)->value) instead.


Side notes:

  1. Always check the return value of a memory-management function, if the allocation were successful.

F.e.:

Mychar *newlinkPtr = calloc(1, sizeof(Mychar));
if (newlinkPtr == NULL)
{
    fputs("Allocation failed!", stderr);
    exit(1);
}
  1. (Probably just a copy & paste mistake but worth to mention) - You forgot to #include <stdlib.h>, which is necessary to use calloc().

Result:

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


struct mychar {
    char value;
    struct mychar *nextPtr;
};

typedef struct mychar Mychar;


void insert(Mychar **, char );    
void printlist(Mychar **);


int main (void) {
    Mychar *startPtr = NULL;

    insert(&startPtr, 'b');

    printlist(&startPtr);

}


void insert(Mychar **sPtr, char myvalue){
    Mychar *newlinkPtr = calloc(1, sizeof(Mychar));
    if (newlinkPtr == NULL)
    {
        fputs("Allocation failed!", stderr);
        exit(1);
    }

    if (*sPtr == NULL){    
        newlinkPtr->value = myvalue;
        newlinkPtr->nextPtr = *sPtr;    
        *sPtr = newlinkPtr;    
    }
}


void printlist(Mychar **startPtr){
    printf("%c\n", (*startPtr)->value);    
}

Output:

b
  • @Mnkisd I don´t know. The first maybe was because my answer wasn´t fulfilled at that point of time. The second I guess just someone who followed the action. I can´t see that my answer has a fault. If they see something, convention is to hint and not to only downvote. Maybe even asymphatics? IDK. – RobertS supports Monica Cellio May 23 '20 at 12:17