Double Pointer

Thread Starter

Kittu20

Joined Oct 12, 2022
433
As I know pointer can store the address of another variable.

In the program I have a pointer variable ptr which stores the address of the variable a. I have another pointer variable dptr which stores the address of the first pointer ptr.

C:
#include<stdio.h>

int main ()
{
    int a = 10;
    int *ptr = &a;
    printf("location of ptr %p \n", &ptr);
    int *dptr = &ptr;
    printf(" dptr hold address of ptr is : %p", dptr);
    return 0;
}
location of ptr 0061FF14
dptr hold address of ptr is : 0061FF14

double pointer holds the address of the first pointer.

Because if I want to store the address of the first pointer, then I declare two pointers.

@WBahn why should we use double pointer? While we have pointer that can do the same thing as double pointer do?
 

WBahn

Joined Mar 31, 2012
29,883
I've actually used up to five stars.

The simplest example of where two-star pointers make sense is an array of strings.

Say that we want to store the following names: "Bob", "Fred", "Susan".

These will be stored as an array of pointers, where each pointer (three total) point to a section of memory containing one of these strings.

But we also need a pointer to the array itself. But what is it an array of? It's an array of pointers!

char **myarry;

Think of it like this:

int *ptr;

This is a pointer that points to an array of values of type int (that array might only contain one value, but that's still an array).

(char *) *ptr;

This is a pointer that points to an array of values of type char *

Another example are multidimensional arrays (which is where I ended up with five-star pointers).
 

Thread Starter

Kittu20

Joined Oct 12, 2022
433
i read the full link but i can't find the answer to my question

If I have a pointer variable so I can store its address in two ways.

Method 1: I will declare another pointer variable and assign the address of the first pointer to it.

Method 2: I will declare double pointer variable and assign the address of the first pointer to it.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
433
I've actually used up to five stars.

The simplest example of where two-star pointers make sense is an array of strings.

Say that we want to store the following names: "Bob", "Fred", "Susan".
Program store three strings

C:
#include <stdio.h>

int main()
{
    int i;
    
    char array[][10] = { "Bob", "Fred", "Susan" };

    
    for (i = 0; i < 3; i++)
        printf("%s\n", array[i]);

    return 0;
}
Bob
Fred
Susan
 

WBahn

Joined Mar 31, 2012
29,883
And 'array' is a pointer to an array of pointers to characters.

Doing it this way is also restrictive. You are assuming that no name is longer than nine characters and that you know the names at the time you wrote the code.

Write a program that asks the user for how many names they want to enter and then asks then to enter the names. You don't know in advance how many names or how long they might be.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
433
Write a program that asks the user for how many names they want to enter and then asks then to enter the names. You don't know in advance how many names or how long they might be.
I am stuck in a problem. I want to get three strings whose size is not greater then five characters without string.h

I can get one string using following program

C:
#include<stdio.h>

int main ()
{
    int i = 0;  char array[5];
 
    printf("Enter string \n");
 
    for ( i = 0; i < 5; i++)
    {
        scanf("%c", &array[i]);
    }
 
    for ( i = 0; i < 5; i++)
    {
        printf("%c", array[i]);
    }
 
    return 0;
}
I want to get 3 strings so I wrote code. But Program doesn't print expected output.
C:
#include<stdio.h>

int main ()
{
    int i, j = 0;
 
    char array[3][5];
 
    printf("Enter string \n");
 
    for ( i = 0; i < 3; i++)
    {
        for ( j = 0; j < 5; j++)
        {
            scanf("%c", &array[j]);
        }
    }
 
    for ( i = 0; i < 3; i++)
    {
        for ( j = 0; j < 5; j++)
        {
            printf("%c", array[j]);
        }
     
    }
 
    return 0;
}
Why code gives a strange output ?
output
Code:
Enter string
red
black
green
        ♫‼↑↔    ♫‼↑↔    ♫‼↑↔
 

dcbingaman

Joined Jun 30, 2021
1,065
You have it more complicated than it needs to be:
1673621284950.png

Of course this is very unsafe code as nothing prohibits the user from entering a string longer than 5 chars.
 

WBahn

Joined Mar 31, 2012
29,883
But what if the name entered is "Jeremiah"?

You started this thread because you wanted to know when you might use a double pointer. Yet you are going out of your way to refuse to use a double pointer.

So I gave you a case where using a double pointer is a valid approach, namely get names from the user in which you don't know how many names they will enter or how long they might be, and you change the problem to having exactly three names, none of which are longer than five characters.

And then you implement things wrong even under those constraints. So let's start there.

Code:
#include<stdio.h>

int main ()
{
    int i, j = 0;

    char array[3][5];
You have allocated memory for exactly 15 characters. But that remember that a string has to have a NUL character at the end, so you can only accommodate three strings of no more than four characters each.

Code:
    printf("Enter string \n");

    for ( i = 0; i < 3; i++)
    {
        for ( j = 0; j < 5; j++)
        {
            scanf("%c", &array[j]);
        }
    }
First off, for each value of i you are writing your input to the exact same locations within your array.

Second, remember what I said about array being an array of pointers?

If you have a 2D array, then array[i] is NOT the ith element of the array, it is a pointer to the ith row of the array, so the address of array[0]. So you are not writing things to where you think you are.

Then, you are getting characters one at a time and insisting that there be exactly five characters, And what about the NUL terminator? You are asking scanf() to get a character, not a string, so it doesn't know anything about NUL terminators.

Code:
    for ( i = 0; i < 3; i++)
    {
        for ( j = 0; j < 5; j++)
        {
            printf("%c", array[j]);
        }
     
    }

    return 0;
}
You are making mostly the same mistakes here. How can your print statement print out anything different when i=2 as it did when i=0 since the only thing what you are printing depends upon is the value of j?


The scanf() function is nototiously poorly behaved and should never be used. It makes assumptions about what to do in different situations and can't handle input that is not aligned with what it is expecting. Use fgets() instead. That just gets the data from the user and gives it to you exactly as it was entered and let's you vet it based on what the requirements are for your problem.
 

WBahn

Joined Mar 31, 2012
29,883
Perhaps this will help you see where the pieces parts are:

Code:
#include <stdio.h>

int main(void)
{
    char array[3][5] = {"ABCD", "EFGH", "IJKL"};
    
    printf("Array contents:\n");
    for (int i=0; i< 3; i++)
    {
        printf("%s ", array[i]);
        for (int j = 0; j < 5; j++)
        {
            printf(" (%3i)", array[i][j]);
        }
        printf("\n");
    }
    
    printf("Array pointers:\n");
    printf("   Base: %p\n", array);
    for (int i=0; i< 3; i++)
    {
        printf("array[%i] is %p (offset: %i)\n", i, array[i], (char *) array[i] - (char *) array);
    }
    
    return 0;
}
One thing to note is that the & operator works differently depending on whether the variable is a pointer or if it is an array.

int *ptr;
int array[1];

ptr is the address where some int is stored and &ptr is the address where the pointer is stored.
array is the address where some int is stored and &array is the same thing.
 

WBahn

Joined Mar 31, 2012
29,883
Also, your declaration for main should be

int main(void)
or
int main(int argc, char* argv[])

The latter is if you want to get command line arguments.

Note that the latter is functionally equivalent to
int main(int argc, char* *argv)

And there's an example of a double pointer.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
433
Write a program that asks the user for how many names they want to enter and then asks then to enter the names. You don't know in advance how many names or how long they might be.
I am allowing maximum 100 characters in the name

C:
#include<stdio.h>
#include<string.h>

int main()
{
    int i,  N;
  
    printf("how many names you want to enter : ", N);
    scanf("%d", &N);
    printf(" You want %d names \n", N);
  
    int array[N][100];
  
    for (i = 0; i < N; i++)
    {
        scanf("%s", array[i]); 
    }

    printf(" \n");
  
    for (i = 0; i < N; i++)
    {
        printf("%s\n", array[i]);
        
    }

    return 0;
}
Program Output
Code:
how many names you want to enter : 3
You want 3 names
bob
stev
john

bob
stev
john
 

nsaspook

Joined Aug 27, 2009
12,843
I am allowing maximum 100 characters in the name

C:
#include<stdio.h>
#include<string.h>

int main()
{
    int i,  N;
 
    printf("how many names you want to enter : ", N);
    scanf("%d", &N);
    printf(" You want %d names \n", N);
 
    int array[N][100];
 
    for (i = 0; i < N; i++)
    {
        scanf("%s", array[i]);
    }

    printf(" \n");
 
    for (i = 0; i < N; i++)
    {
        printf("%s\n", array[i]);
       
    }

    return 0;
}
Program Output
Code:
how many names you want to enter : 3
You want 3 names
bob
stev
john

bob
stev
john
A buffer overflow/crashing nightmare with random sized inputs.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
433
Apparently you don't actually want to learn about using double pointers, since you refuse to try to use them. So good luck.
of course I want to learn but i was struggling concept of double pointer with array

Perhaps this will help you see where the pieces parts are:
I don't understand what's happen inside loop, specially (char *) array - (char *) array ?
Code:
    for (int i=0; i< 3; i++)
    {
        printf("array[%i] is %p (offset: %i)\n", i, array[i], (char *) array[i] - (char *) array);
    }
   
    return 0;
}
 

WBahn

Joined Mar 31, 2012
29,883
I don't understand what's happen inside loop, specially (char *) array - (char *) array ?
Code:
    for (int i=0; i< 3; i++)
    {
        printf("array[%i] is %p (offset: %i)\n", i, array[i], (char *) array[i] - (char *) array);
    }

    return 0;
}
I'm just calculating the distance between the two pointers (i.e., the offset of the first from the second). Since they aren't of the same type, they can't be subtracted from each other, so they are both cast to (char *). This makes the difference equal to the number of char variables that can fit between them. Since a char is almost universally one byte, this makes the result equal to the number of bytes between the two pointers.
 

WBahn

Joined Mar 31, 2012
29,883
So let's do a deep dive and see if we can understand the behavior of the code you presented awhile back

ORIGINAL CODE
Code:
#include<stdio.h>

int main ()
{
    int i, j = 0;
 
    char array[3][5];
 
    printf("Enter string \n");
 
    for ( i = 0; i < 3; i++)
    {
        for ( j = 0; j < 5; j++)
        {
            scanf("%c", &array[j]);
        }
    }
 
    for ( i = 0; i < 3; i++)
    {
        for ( j = 0; j < 5; j++)
        {
            printf("%c", array[j]);
        }
     
    }
 
    return 0;
}
On my machine, this produced the following:
Code:
Enter string
red
black
green
        ♫‼↑↔    ♫‼↑↔    ♫‼↑↔
I expect rather unpredictable results, but what I didn't expect is that I was actually produce the same results as your code. I expected that the results would be quasi-random because they would be affected by whatever junk happened to be in memory. For me to recreate exactly what you have implies that the code is writing specific values to all of the locations that determine the final output.

Let's see what happens with your code if I enter different strings.

Code:
Enter string
a
b
c
d
e
f
        ♫‼↑↔    ♫‼↑↔    ♫‼↑↔
Notice that I had to enter a total of six strings (i.e., hit the enter key six times), but got the exact same results.

So let's see what is getting written where.

The first change I made was to just print out some telltales of what the values of the variables are at each stage. The intent was to show you that scanf() is not doing what you apparently think it does, but it revealed something else, as well.

First, with your inputs:
Code:
Enter string

DATA ENTRY
[i=0](j=0)red
(j=1)(j=2)(j=3)[i=1](j=0)black
(j=1)(j=2)(j=3)[i=2](j=0)(j=1)(j=2)green
(j=3)   ♫‼↑↔    ♫‼↑↔    ♫‼↑↔
Next, with my one-character strings.
Code:
Enter string

DATA ENTRY
[i=0](j=0)a
(j=1)(j=2)b
(j=3)[i=1](j=0)c
(j=1)(j=2)d
(j=3)[i=2](j=0)e
(j=1)(j=2)f
(j=3)   ♫‼↑↔    ♫‼↑↔    ♫‼↑↔
Notice a couple of things. First, after entering 'red', the loop executes several times before I get to enter another string.

This is the behavior I expected and wanted to point out.

When you execute scanf(), it does NOT go and get what you type at the keyboard. Instead, it goes and fetches things from the keyboard buffer. Only if the buffer is empty does it ask the operating system go and let you type something in. At that point, the operating system puts your program on hold and lets you typing things, which it transfers to the buffer, until you finally hit ENTER, at which point it adds the last thing, the newline that results from the ENTER press, before transferring control back to your program.

So when you typed "red", the loop executed a total of four times. First it got the 'r', then the 'e', then the 'd', and finally the '\n'.

But another thing to notice is that the inner loop did NOT execute five times. In fact, it terminated after j=3.

So let's instrument the code a bit and see what is getting written where.

I wrote the following function:

Code:
void dump(void *p, int n)
{
    printf("\n--------------------\n");
    for (int i = 0; i < n; i++)
        printf("%2X ", (unsigned char) ((char *)p)[i]); 
    printf("\n--------------------\n");
}
This function takes a pointer (of any type) as well as the number of bytes to display from that point and it then displays them in hex between a short pair of lines. There's a newline at the very beginning and at the very end to make the output neat regardless of where the cursor is, but this tends to result in extra blank lines.

I then made a call to this function right after the scanf() call, telling it to print out 30 bytes starting at the base address of 'array'.

This produced the following output (I manually removed the excess blank lines).
Code:
Enter string
ABC
--------------------
41  0  0  0  0  0  0 A0 13 B3  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
41  0  0  0  0 42  0 A0 13 B3  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
41  0  0  0  0 42  0 A0 13 B3 43  0  0  0  0  2  0  0  0  0  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
41  0  0  0  0 42  0 A0 13 B3 43  0  0  0  0  A  0  0  0  0  0  0  0  0  0  0  0  0  0  0
--------------------
DEF
--------------------
44  0  0  0  0 42  0 A0 13 B3 43  0  0  0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
44  0  0  0  0 45  0 A0 13 B3 43  0  0  0  0  1  0  0  0  1  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
44  0  0  0  0 45  0 A0 13 B3 46  0  0  0  0  2  0  0  0  1  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
44  0  0  0  0 45  0 A0 13 B3 46  0  0  0  0  A  0  0  0  1  0  0  0  0  0  0  0  0  0  0
--------------------
GHI
--------------------
47  0  0  0  0 45  0 A0 13 B3 46  0  0  0  0  0  0  0  0  2  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
47  0  0  0  0 48  0 A0 13 B3 46  0  0  0  0  1  0  0  0  2  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
47  0  0  0  0 48  0 A0 13 B3 49  0  0  0  0  2  0  0  0  2  0  0  0  0  0  0  0  0  0  0
--------------------
--------------------
47  0  0  0  0 48  0 A0 13 B3 49  0  0  0  0  A  0  0  0  2  0  0  0  0  0  0  0  0  0  0
--------------------
        ♫‼↑↔    ♫‼↑↔    ♫‼↑↔
And this reveal pretty much all.

Notice that after "ABC" is entered, the ASCII code for 'A' (0x41) is placed at array[0], which is actually array[0][0], but when 'B' is placed at array[1], it is actually being placed at array[1][0]. That's because array[j] is a pointer to the jth row of the 2D array.

But check out what is happening out there at the 16th position in the array. The first line is 0, then 1, then 2, then A.

What gives?

Simple, the array only has twelve bytes of space allocated to it. So the 16th position is NOT part of the array. In fact, it is where the variable 'j' is being stored, which is why it is counting up each time. If you look four bytes further, you see a memory location that is being incremented more slowly. That's the variable 'i'. Why four bytes further? Because j takes up four bytes (as down i).

So why it is getting set to 0xA? Because that is the newline character (decimal 10) that is placed in the input buffer when you hit the ENTER key. But here, you are overwriting j and setting it equal to 10, which is not less than 5, and so the inner loop exits after completing the fourth pass, not the fifth.

If you change the size of the strings or how long you think each of them is, you would get completely different behavior.

Now, why is it printing out that particular output line?

The first part is why is it printing out the same set of characters three times?

That one is easy. Because on all three passes through the loop, you are telling it to print the exact same thing.

Now the trickier question -- why is each pass printing out that particular thing?

First off, it turns out that it's not. I get one of several outputs, depending on what the address of 'array' ends up being.

Remember, array[j] is a pointer, so you are asking it to print a pointer as a character. The best it can do is take the least significant byte of the pointer and treat that as an ASCII code.
 

WBahn

Joined Mar 31, 2012
29,883
I'm working off the code you're writing trying to help you understand why it is behaving the way that it is.

If you want an example of using a double pointer, here:

Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    #define BUFFERSIZE 20
    char buffer[BUFFERSIZE];
   
    printf("How many players? ");
    fgets(buffer, BUFFERSIZE, stdin);
    int players = atoi(buffer);
   
    char **playerNames;
   
    playerNames = (char **) malloc(players * sizeof(*playerNames));
   
    for (int player = 0; player < players; player++)
    {
        printf("Name for player #%i: ", player);
        fgets(buffer, BUFFERSIZE, stdin);
        playerNames[player] = (char *) malloc(sizeof(char) * strlen(buffer));
        strcpy(playerNames[player], buffer);
    }

    printf("Here are your players:\n");
    for (int player = 0; player < players; player++)
        printf("%i) %s\n", player, playerNames[player]);
       
    return 0;
}
Run it and see if you can spot a behavior that you probably don't expect.

When I get back later today I can explain why it is doing that and how to deal with it. That will also put be into a position to tell you how you can deal with a really, really long name.

Also, do you spot something that I am NOT doing here that I should (as part of proper housekeeping)?
 
Top