Thread: Trying to understand pointers and pointers to pointers

  1. #1
    Registered User
    Join Date
    Jan 2017
    Posts
    16

    Trying to understand pointers and pointers to pointers

    Hi,

    I am trying to get a better understanding of pointers and pointers to pointers.

    I get that int a; is a variable that has a value that is an integer, and that int *b; is a variable that is a pointer to something that has a value that is an int, and that int **c is a pointer to a pointer to something that has a value that is an int.

    The code I was testing with (see below) seems to indicate that I can keep adding an * to increase the ... Umm ... "depth?" of how far I am pointing.

    Code:
    #include <stdio.h>
    int main(int argc, char *argv[]) {
    	int a;
    	int *b;
    	int **c;
    	int ***d;
    	int ****e;
    	
    	
    	b=&a;
    	c=&b;
    	d=&c;
    	e=&d;
    
    	a=20;
    
    	printf("\na=%d\n",a);
    	printf("\n*b=%d\n",*b);
    	printf("\n**c=%d\n",**c);
    	printf("\n***d=%d\n",***d);
    	printf("\n****e=%d\n",****e);
    	return 0;
    }
    This seems to mean that any function I create needs to KNOW the exact "depth?" of a given variable passed by reference. Is that true? Do I really need to do something like this:

    Code:
    int somefunc(int **********varname){
    	/* some code */
    }
    Or is there some syntax that can be used that says something like: this variable is a pointer to pointers that eventually leads to a block of memory that contains an int.

    I understand that what I am asking maybe completely stupid and pointless (pun not intended but recognized) and I don't know that I would ever need or want something like this, but I want to understand it all better.

    Thanks for any input.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    You obviously need to know the exact "depth" (levels of indirection) in order to use the variable. However, you could cast it to void* and also pass the depth. I've never seen that done. The following code could be problematic. It assumes that a int**, int***, int****, etc (all pointers to pointers) are all essentially the same underlying representation, although it doesn't assume that int* (pointer to int) is necessarily the same as those.
    Code:
    #include <stdio.h>
    
    void func(void *p, int depth) {
        while (depth-- > 1) p = (void*)*(int**)p;
        printf("%d\n", *(int*)p);
    }
    
    int main() {
        int a = 42;
        int *b = &a;
        int **c = &b;
        int ***d = &c;
        func((void*)b, 1);
        func((void*)c, 2);
        func((void*)d, 3);
        return 0;
    }

  3. #3
    Registered User
    Join Date
    Jan 2017
    Posts
    16
    Quote Originally Posted by algorism View Post
    You obviously need to know the exact "depth" (levels of indirection) in order to use the variable. ...
    That's what I was kind of assuming based on what I have learned so far, but I needed confirmation.

    The vast majority of my programming experience is from using high level languages like PHP, JavaScript, Perl, Python, etc., and it's difficult after many years of that kind of thing to really grok the lower level that C involves.

    So anyway, If the language requies us to KNOW the level of indirection in order to use a variable, and a function can't KNOW the level of indirection that a program in the future might be dealing with, it seems the assumption must be that the responsibility for conformity lies with the calling code, not the code called. Thus a function in a library states what it is expecting, like "char *varname" and the code calling it is responsible for passing that, even if that means it has to assign to a temporary variable, or use lots of "*" in its call, or even use a cast of some kind. Correct?

    For example my function that wants to do something with a pointer to some characters would be declared with just "char *varname", and at the point in the hypothetical code where I am dealing with something that is many levels of pointers deep I would "know" what that depth was and when I call the function I would do something like retval=somefunc(****varname);

    True? False? Sort of on the right track? Completely missed the point?

    Thanks.

  4. #4
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    I guess that's correct. It's pretty much a moot point since it would be extremely rare for levels of indirection to go that deep. The common depths are just 1 or 2. Obviously 3 is useful, too. 4 or more is getting pretty hairy, possibly indicative of some kind of design flaw.

    Anyway, it's best to just think of them all as different types. Obviously a function needs to know the type that is being passed in and the caller needs to know the type to pass. You could even give them typedefs to hammer that home, although that often just obscures the situation.

    BTW, although pointers don't exist in higher-level languages, indirection still exists.

  5. #5
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by algorism View Post
    ... although pointers don't exist in higher-level languages ...
    The high level language PL/1 has pointers. There were some versions of Fortran, where an index normally starts at 1, so array[1] would be the first element and array[0] would be the address of the array. Changing array[0] would effectively change the address of array[1] through array[n].

    Quote Originally Posted by algorism View Post
    indirection still exists
    On some older processors, the most significant bit of memory was used as an indirect bit. This could lead to an unlimited number of indirect links. As a debugging aid, one location in memory would be set to indirect to itself, and uninitialized memory filled to cause an indirect to lock up on that one location. The issue with this design is that interrupts would be delayed during a sequence of indirections.

  6. #6
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by rcgldr View Post
    The high level language PL/1 has pointers. There were some versions of Fortran, where an index normally starts at 1, so array[1] would be the first element and array[0] would be the address of the array. Changing array[0] would effectively change the address of array[1] through array[n].
    I mostly just meant the scripting languages he mentioned. Pretty much all languages have some kind of indirection, but not necessarily pointers. ("We can solve any problem by introducing an extra level of indirection." - David Wheeler)

    Quote Originally Posted by rcgldr View Post
    On some older processors, the most significant bit of memory was used as an indirect bit. This could lead to an unlimited number of indirect links. As a debugging aid, one location in memory would be set to indirect to itself, and uninitialized memory filled to cause an indirect to lock up on that one location. The issue with this design is that interrupts would be delayed during a sequence of indirections.
    That's pretty weird. You're saying that the value representation (not the machine language instruction) indicates whether or not a value is a pointer. Very interesting.

  7. #7
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by rcgldr View Post
    On some older processors, the most significant bit of memory was used as an indirect bit. This could lead to an unlimited number of indirect links. As a debugging aid, one location in memory would be set to indirect to itself, and uninitialized memory filled to cause an indirect to lock up on that one location. The issue with this design is that interrupts would be delayed during a sequence of indirections.
    Quote Originally Posted by algorism View Post
    That's pretty weird. You're saying that the value representation (not the machine language instruction) indicates whether or not a value is a pointer. Very interesting.
    In the case of the HP 2100, 16 bit computer, bit 15 was the direct / indirect bit for both memory instructions and memory addresses access via indicection. When an indirection occurred, an address was loaded and bit 15 was again used as another possible level of direct / indirect bit, and an indirect infinite loop was possible. Normally the cpu would eventually load an address with bit 15 not set, and then that address was used to load or write the actual 16 bit data. Loads and stores could only load 16 bit words, and the default instruction set did not have a byte access. There was an optional micro-controller option that allowed the instruction set to be extended, which added byte indexing off a base address.

    The older still CDC 3000 24 bit series operated the same way. 24 bit instructions, 15 bit addresses for words, (max 32k 24 bit words) or 17 bit addresses for characters (different instructions). Bit 17 was the indirect bit, and operated the same way as the later HP 2100. There was a store instruction that replaced only the address field of an instruction, a classic case of self modifying code. The boolean function names were different, or is "selective set", xor is "selective complement", ~and is "selective clear".

    http://archive.computerhistory.org/resources/text/HP/HP.2100.1972.102646165.pdf


    http://archive.computerhistory.org/resources/text/CDC/CDC.3200.1963.102646086.pdf

    Last edited by rcgldr; 01-23-2017 at 02:14 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 43
    Last Post: 05-23-2013, 03:01 PM
  2. Understand pointers
    By Aphex in forum C Programming
    Replies: 3
    Last Post: 08-12-2010, 09:07 PM
  3. i cant understand something in pointers
    By nik2 in forum C Programming
    Replies: 2
    Last Post: 02-12-2010, 01:26 PM
  4. Trying To Understand Pointers!
    By pobri19 in forum C Programming
    Replies: 4
    Last Post: 05-08-2008, 01:28 AM
  5. Something I still don't understand about pointers
    By Extol in forum C++ Programming
    Replies: 11
    Last Post: 03-01-2003, 06:20 AM

Tags for this Thread