0
#include <stdio.h>


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

typedef struct mychar Mychar;


void insert(Mychar **, char );

int main(){
    Mychar *startPtr = NULL;    // line 13

    insert(&startPtr, 'b');

}

void insert(Mychar **sPtr, char myvalue){

    if (**sPtr == NULL){    // if I put double ** it doesn't work. it works only with one *
        // do stuff
    }

I got this error:

liste_collegate.c:13:13: error: invalid operands to binary expression ('Mychar' (aka 'struct mychar') and 'void *')
        if (**sPtr == NULL){
            ~~~~~~ ^  ~~~~

I really don't get why if I initialize startPtr at line 13 with Mychar *startPtr = NULL; and then I pass the address of that pointer to insertfunction, I can't get the value if I put two ** but it works only if I put only one *.

Shouldn't I dereferenciate two times in order to reach value NULL? I mean, if I am passing an address of a pointer to a function, that function will need to derefernciate one time to reach the value of the address inside the first pointer, and then another time to reach the real value in that address...

Why doesn't it work?

Of course I know that there must be something wrong, just I don't know why.

Mnkisd
  • 504
  • 2
  • 12
  • Your compiler is obligated to issue a diagnostic message for this incorrect code (as well as for the incorrect code implied by the comment in your code). – EOF May 23 '20 at 13:19
  • @EOF Of course I know that there must be something wrong, just I don't know why. – Mnkisd May 23 '20 at 13:20
  • They're both wrong. The first is assigning `3` to a `Mychar *`, which is not meaningful, but an implementation defined conversion does exist, so the compiler accepts it. (If you compile with `-Wall`, which you should be, you will receive a warning.) The second is assigning `3` to ` Mychar` for which no conversion exists, so this is a mandatory error. – Raymond Chen May 23 '20 at 13:24
  • Your compiler is *required* to tell you where you are wrong in this code. However, I have a suspicion that your compiler is not following that obligation, because the error is earlier than the point you are confused about. So, either replace your compiler with a standard-conforming compiler, or file a bug report with the compiler vendor for not issuing a diagnostic message for a constraint violation assigning an integer to a pointer without cast. – EOF May 23 '20 at 13:24
  • @RaymondChen @EOF I updated the thread replacing `3` with `NULL`, but still doesn't work – Mnkisd May 23 '20 at 13:29
  • @EOF Compilers are not required to diagnose assigning an integer to a pointer. They *are* required to diagnose assigning an integer to a structure. Mnkisd: Your change didn't fix anything. Assigning NULL to a structure is not valid either. – Raymond Chen May 23 '20 at 13:32
  • @RaymondChen incorrect: C11 draft standard n1570: *6.5.16.1 Simple assignment Constraints 1 One of the following shall hold: [[none of these hold for assigning an integer to a pointer]]*. Also, *5.1.1.3 Diagnostics 1 A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint[...]*. – EOF May 23 '20 at 13:36
  • Wrong comparison. you are comparing the value of **sPtr (struct mychar) to NULL. Which of the pointers you are trying to test? **sPtr is the value. *sPtr is pointer to the value. sPtr is pointer to the pointer to the value. – niry May 23 '20 at 13:40
  • @niry in fact... I am trying to test **sPtr (the value)... but like I said, it doesn't work. – Mnkisd May 23 '20 at 13:42
  • The value can never be NULL. Wrong type. – niry May 23 '20 at 13:44
  • @niry why? I'm new to C, I am trying to learn. Sorry for dumb question – Mnkisd May 23 '20 at 13:49
  • 1
    `**sPtr` is a `Mychar` structure. Structures are not pointers. They cannot be compared with `NULL`, which is a pointer. Do you want to check whether the `Mychar` structure has a specific `value`? Or that its `nextPtr` is null? Or maybe you aren't interested in the `Mychar` at all. From context you probably want to see if the `Mychar*` pointer is null, which is a single deference. You need to sit down and draw pictures to figure out what you have and what you want. – Raymond Chen May 23 '20 at 14:13
  • What @RaymondChen said. Also look at https://stackoverflow.com/questions/141720/how-do-you-compare-structs-for-equality-in-c – niry May 24 '20 at 05:35
  • @RaymondChen ok, NULL is a pointer. But how could I compare to, say.. 3 replacing NULL? – Mnkisd May 24 '20 at 07:53
  • You cannot compare ` Mychar` with `3`. They are not compatible types. I think the problem is that you are writing a program that is too complicated. You're trying to learn structures, pointers, and double-indirect pointers all at once. That's too much to try to learn all at once. First learn about structures, get comfortable with them, understand why `Mychar s; if (s == 3)...` does not make sense. Then you can move on to pointers. And then to double-indirect pointers. But don't try to learn all three at once. – Raymond Chen May 24 '20 at 13:22

3 Answers3

0

"Shouldn't I dereference two times in order to reach value NULL??"

No.

It is because NULL is a macro for assigning or comparing a pointer to a null pointer (a pointer which points to no (valid) memory); It is used for pointers only, not it´s referenced objects - the object they point to (unless the referenced object is also a pointer and you want to check if for NULL, but that´s not the case here).


**sPtr is a pointer to pointer to type Mychar. If you dereference sPtr ( means *sPtr) you access the pointer it is pointing to (actually startPtr in main), which is correct for checking startPtr for 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.

Feel free to ask for further clarification.

  • I updated the thread replacing `3` with `NULL` . Also, my goal wasn't reach `value`. I'm just playing with pointers content to "build" my linked list. – Mnkisd May 23 '20 at 13:29
  • @Mnkisd Updated my answer. If you do not understand a certain part, feel free to ask. – RobertS supports Monica Cellio May 23 '20 at 14:24
  • Thanks for answer! If I want to compare to 3 (that's not a pointer like NULL) instead of NULL? How could I do that? – Mnkisd May 24 '20 at 07:57
  • @Mnkisd `if((*sPtr)->value == 3)`. – RobertS supports Monica Cellio May 24 '20 at 08:44
  • No, I didn't mean the value INSIDE the struct. I mean the value inside the pointer in line 13 – Mnkisd May 24 '20 at 08:46
  • @Mnkisd Why should you want to do that? With that you compare the value of `3` to the pointer itself, which makes no sense.The pointer does not point to anything like `3`. A pointer can only point to the memory address of a valid object. – RobertS supports Monica Cellio May 24 '20 at 09:08
  • You are right.... I think I got it now, thanks. One question, if may I... I don't get why to make linked lists I should pass to (in my case) `insert` function the `&`address of my `startPtr`. And also, don't get why should I have in the arguments of my `insert`function two `**` for `sPtr` – Mnkisd May 24 '20 at 09:20
  • 1
    I don´t know your full assignment exactly, but probably it is because you need to **modify** the pointer `startPtr` in `main` itself from inside the function `insert`. Therefore, you need to 1. pass the pointer by reference (actually obtain the address of `startPtr` by using the `&` operator at the call to `insert` and 2. The respective parameter in `insert` needs to be a pointer to pointer (`**`), because `sPtr` actually should point **to a pointer**. Being `sPtr` a single pointer (`*`) would be misplaced here. – RobertS supports Monica Cellio May 24 '20 at 09:33
  • If may I ask you, what would have happened if I had put in `insert`function arguments one only * for sPtr instead of two **? – Mnkisd May 24 '20 at 10:51
  • @Mnkisd If you would pass `startPtr` by reference (with `&`), it should give you a warning of incompatible pointer types. If you don´t use `&` preceding `startPtr` as argument in the call to `insert` you would just pass the `NULL` pointer by value to `sPtr`, if `sPtr` is defined as `myChar* sPtr`. – RobertS supports Monica Cellio May 24 '20 at 17:32
0

enter image description here

In main(), you defined startPtr to be a pointer pointing to a location that is of type Mychar. In the above picture, your startPtr is similar to int *p. You passed the address of that startPtr to insert function. That is, you passed something similar to int **pp in the above image.

When you just hit sPtr, you're seeing the value inside that variable, which is something similar to the value contained in **pp in the above image (0x450).

When you say *sPtr, you're dereferencing the value inside sPtr, which is something like the value contained in *p (0x200), which in your case is 3. So, dereferencing once is enough. When you dereference twice, you're dereferencing 3, which may cause segmentation fault if the address 3 is not part of your process.

0

Did you see the warning and the error when you compile the code:

Mychar *startPtr = 3;    // line 13

This line raises the warning:

warning: initialization makes pointer from integer without a cast [-Wint-conversion]

if (**sPtr == 3)

An this line raises the error:

error: invalid operands to binary == (have ‘Mychar {aka struct mychar}’ and ‘int’)

For the warning, you try to assign the pointer to an integer, maybe you want something like:

Mychar startValue;
startValue.value = 3;
// then initialize the pointer by making it point to address of startValue
Mychar *startPtr = &startValue;

For the error (answer with your update), you try to compare a value with NULL pointer. As the your last question, NULL is use for only pointer, so you can compare the pointer NULL with only another pointer. Maybe you can:

if (*sPtr == NULL) {}
// OR
if (*sPtr == NULL) {}
// But not
if (**sPtr == NULL) {}
Hitokiri
  • 3,607
  • 1
  • 9
  • 29