C difference between pointers

Discussion in 'Programmer's Corner' started by kubeek, Jan 7, 2013.

  1. kubeek

    Thread Starter AAC Fanatic!

    Sep 20, 2005
    4,670
    804
    Hi, i am stuck on this problem - I crawl through an array using ptr++ to save some instructions, and after the deed I need to know how many items I went through.
    Code ( (Unknown Language)):
    1. unsigned char a[20];
    2.     unsigned char *ptr;
    3.     ptr=a;
    4.  
    5.     ptr++;
    6.     ptr++;
    7.     int x=(&ptr-&a);
    8.     printf("\n%d",x);
    prints -3 regardless of how many ptr++ I do, which obviously is not right. Any clues how to achieve this?
     
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Usually what I do is have a counter increment each time t
    Code ( (Unknown Language)):
    1.  
    he element is accessed, that way, all you need is the pointer to the first element, and the offset/counter value. Like this:
    Code ( (Unknown Language)):
    1.  
    2. unsigned char a[20];
    3.     unsigned char *ptr;
    4.     ptr=a;
    5.    EDIT: unsigned char counter = 0; //can't believe I missed that!
    6.  
    7.     counter++;
    8.     counter++;
    9.     int x=counter;
    10.     printf("\n%d",x);
    11.  
    12.  
    If you still want to do it the way you described, you should be able to do this:

    Code ( (Unknown Language)):
    1.  
    2.     unsigned char a[20];
    3.     unsigned char *ptr;
    4.     ptr=a;
    5.  
    6.     ptr++;
    7.     ptr++;
    8.     int x=(ptr-a);//these are already pointers
    9.     printf("\n%d",x);
     
    Last edited: Jan 7, 2013
  3. kubeek

    Thread Starter AAC Fanatic!

    Sep 20, 2005
    4,670
    804
    Thanks, looks like I will use iterator after all.
     
  4. WBahn

    Moderator

    Mar 31, 2012
    17,737
    4,789
    The expression (&ptr-&a) calculates the distance (in increments of the amount of memory required to store a pointer to an unsigned char) between where ptr is stored and where a is stored.

    The variable ptr, whose value is a memory location, is still a variable that is stored at some memory location and &ptr evaluates to the address of that location. The meaning of &a is more problematic since a is not a variable in which an address is stored. Without looking through the language spec, I would think that &a when a is an automatic array would be undefined and would return something that depends on the implementation. But perhaps it is specified thatit returns something in particular -- I don't know.

    What you want is simply (ptr-a), namely the address of what ptr is pointing to minus the base address of the array (implicitly divided by the size of the items pointed to). This will be the same as the index within the array of the item pointed to by ptr.
     
  5. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    Surely if you set

    ptr = a;

    then you should calculate the difference using

    int x=(ptr - a);

    not

    int x=(&ptr-&a);

    ?


    Bah, Wbahn's posting got out there 2 minutes before mine! But I'll leave this up anyway.
     
  6. WBahn

    Moderator

    Mar 31, 2012
    17,737
    4,789
    But what is counter equal to (since it is unitialized)?

    If you are going to maintain an counter that serves the same purpose as an index into the array, why use ptr at all. Instead, just use a[counter].
     
  7. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Yeah, I didn't initialize it:eek: should be initialized to 0....gonna make that note now...

    I was doing it the way kubeek had it down so that it wouldn't be much of a stretch to see what I meant...
     
  8. Papabravo

    Expert

    Feb 24, 2006
    10,140
    1,789
    Given the variety of memory architectures, there is absolutely no guarantee that pointer arithmetic will produce meaningful results. What happens if the array occupies two different segments of memory?
     
  9. kubeek

    Thread Starter AAC Fanatic!

    Sep 20, 2005
    4,670
    804
    Thankfully there are no segments in an AVR.
     
  10. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Pointers can get confusing.

    a can be thought of a variable holding a value
    &a is the address location holding that value
    a* the value at the address a in a string, with integers, or different compilers, it can give odd results.

    Usually, &<var> is only for passing a value to a function that will be updated in that function, so that a function can "return" more than one value by modifying the memory of a value in another scope.

    Pointers are one of the biggest reasons for programs to fail, especially after initial testing, then in the field, some odd input happens and it jumps to a function that ends up garbling some data. Tread carefully and read how your specific compiler deals with them, especially after optimization.
     
  11. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Since both a and p point to the very same array then the results are guaranteed to be valid to comparison and arithmetic. See K&R section 5.4.

    There is no such guarantee when a and p point to different things.

    For an array a:

    char a[10];
    char* p1 = &a;
    char* p2 = a;
    char* p3 = &a[0];

    then p1 == p2 == p3, as each is a valid legal way to reference the starting address of the array.
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    And just to add...

    verylongtype a[10];
    verylongtype* p = &a;
    int x;
    p++; p++; p++;
    x = p-a;

    x would yield 3 no matter what the size of the type of a.
     
  13. WBahn

    Moderator

    Mar 31, 2012
    17,737
    4,789
    The principal behaviors of pointer arithmetic are very well defined in C and is independent of segments and such. As one example of the independence, the actual value associated with a NULL pointer may or may not be zero (is usually is not), but all legal arithmetic and logical operations performed on a NULL pointer must behave as though it were.
     
  14. WBahn

    Moderator

    Mar 31, 2012
    17,737
    4,789
    This is also why the difference of two pointers (pointing to places within the same object, which includes any dynamically allocated memory block) is defined but the sum is not.
     
  15. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Here is a curious bit of code & comment from the Microchip C18 stddef.h file:

    Code ( (Unknown Language)):
    1. /* NULL is a simple one. Many compilers define NULL as ((void*)0), which
    2.  * is not best. A pointer to void is a pointer to data and a comparison
    3.  * to a function pointer is a type mismatch and should result in an
    4.  * error. The ANSI/ISO standard makes no guarantees about pointers to
    5.  * data and pointers to code being at all related to one another.
    6.  *
    7.  * Since the standard requires that a pointer comparison to an integral
    8.  * constant value of zero be allowed and is equivalent to a comparison
    9.  * to the NULL pointer constant, we define NULL very simply, as '0'.
    10.  */
    11. #define NULL 0
    The C18 compiler claims ANSI `89 compatibility.
     
  16. WBahn

    Moderator

    Mar 31, 2012
    17,737
    4,789
    Yeah, that makes sense.

    The actual value used for a null function pointer and for a null data pointer do not have to be the same. For that matter, in theory, the actual value for a null pointer to an int and a null pointer to a float and a void pointer would not have to be the same. The compiler knows what kind of pointer each pointer is and can therefore keep track of all of this and make whatever translations are necessary in order to make them all behave the correct way.

    But if you define a constant to be the null value for one of these types and then use that constant to set the value of another type of pointer, the value of that constant may not be recognized as anything special and simply be used.

    I remember when I was first learning C I though I was being real clever to define some symbolic constants as follows:

    #define TRUE (1==1)
    #define FALSE (!TRUE)

    because then, my reasoning went, it didn't matter what actual value was used by the compiler for a logical true or a logical false, my definitions would always work. Well, that's probably valid reasoning, but it is unnecessary since the C standard requires that a logical false always be 0 and a logical true be anything else. So whenI define these symbolic constants now, I simply do

    #define FALSE (0)
    #define TRUE (!FALSE)
     
  17. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Microchip (via their GenericTypeDefs.h) does something similar:

    Code ( (Unknown Language)):
    1. typedef enum _BOOL { FALSE = 0, TRUE } BOOL;    /* Undefined size */
     
Loading...