-1

I understand the concept of pointers and that we use them in functions to optimize the space we use.
What I don't get is the syntax when using them in functions.

Example 1:

void fun(int * a)//that means we declared a pointer to an integer type a
{
  *a+=1; 
}
fun(&b);//calling the function for int b=10;

Example 2:

void fun(int * a)//that means we declared a pointer to an integer type a
{
  a+=1;
}
fun(&b);//calling the function for int b=10;

Question: which one is right and if they are both right what's the difference between the two?

EDIT After AKX's answer: Why do we in a linked list do this then? Shouldn't it be **head instead of *head in the body if we want to change the value of the object and not the adress of the pointer ( double-pointer in this case )??

void push(struct node **head, int data)
{
        struct node* newnode = malloc(sizeof(struct node));
        newnode->data = data;
        newnode->next = *head;
}

push(&head,1);
dreamcrash
  • 47,137
  • 25
  • 94
  • 117
  • The linked list code is your first case, only that the value that you access is a `struct node *`, not an `int`. (The code looks a bit suspect, though: If you only read from `*head`, you don't need a pointer to pointer. For a function with the given signature It is more common to say `*head = newnode` instead (or before) returning the node.) – M Oehm Feb 21 '21 at 19:07
  • @m oehm so saying node * newnode=* head is the same as saying node **head?? –  Feb 21 '21 at 19:09
  • Eh? No. I was saying that your `push` function doesn't really make use of the fact that you can modify the head pointer from the calling function. There are basically two ways to implement pushing a value: `head = push(head, x)` and `push(&head, x)`, where `head` is a `struct node *` and `&head` is a `struct head **`. Your function looks like a mix in between. – M Oehm Feb 21 '21 at 19:15
  • *"which one is right and if they are both right what's the difference between the two?"* - Did you try them to see the difference? – klutt Feb 21 '21 at 20:22

3 Answers3

1

If you have int *p, then *p is the pointed-to value, an int. *p += 1 increments that int. On the other hand, p itself is int *, the pointer. p += 1 increments the pointer, making it point to the next element of the array it points to.

This should print 10 20 35:

#include <stdio.h>
void foo(int *p)
{
     p += 1; /* increment the pointer */
    *p += 5; /* add to the pointed-to int */
}

int main(void)
{
    int a[3] = {10, 20, 30};
    foo(&a[1]);     /* address of / pointer to a[1] */
    printf("%d %d %d\n", a[0], a[1], a[2]);
}

Here,

struct node* push(struct node **head, int data)
{
        struct node* newnode = malloc(sizeof(struct node));
        newnode->data = data;
        newnode->next = *head;
        return newnode;
}

head is a pointer to pointer to struct node, so *head is a pointer to struct node. That's what we want to store in a linked list usually, the pointer to the next piece of data. **head would be a struct node, the element itself, assigning from that would be making a copy of the piece of data.

ilkkachu
  • 6,221
  • 16
  • 30
1

I understand the concept of pointers and that we use them in functions to optimize the space we use.

That’s not why we use them (at least that’s not the primary reason, and on a modern system an int * likely takes up more space than an int) - we use them because that’s the only way to write a new value to the parameter.

Remember that C passes all function arguments by value - any change to the formal argument in the function is not reflected in the parameter in the function call. If your function was written as

void fun( int a )
{
  a += 1;
}

and called as

fun( b );

the value in b would not be affected - a is a completely different object, and any changes to it are not reflected in b. However, when we write

void fun( int *a )
{
  *a += 1;
}

fun( &b );

we’re not updating the value of a, we’re updating the value of the thing a points to, which in this case is b.

Regarding the linked list example, the way it’s written doesn’t require head to be a struct node ** because it’s not getting a new pointer value written to it; you’d need to call it as

list = push( &list, new_value );

for the list pointer to be updated properly.

You’d only pass head as a struct node ** if you wanted to update the head parameter, like so:

void push( struct node **head, int data )
{
  struct node *n = malloc( sizeof *n );
  if ( n )
  {
    n->data = data;
    n->next = *head;  // n->next points to the old head of the list
    *head = n;        // n becomes the new head of the list
  }
}
    

and call it as

struct node *list = NULL;  // list is initially empty

push( &list, 42 );
push( &list, 300 );

etc.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Verbatim based on OP's post:

Example 1 *a=+1; sets the value stored at the location referenced by the pointer to +1.

Example 2 a=+1 makes the pointer point at the memory address 1 (which is likely invalid).

If OP means a += 1:

Example 1 increments the value stored at the location referenced by the pointer (since * is the dereferencing operator).

Example 2 increments the pointer itself, making it point at a different location, and the increment is the pointer type's size (convenient if you have an array).

AKX
  • 152,115
  • 15
  • 115
  • 172