Peeter Joot's Blog.

Math, physics, perl, and programming obscurity.

Address of an array base. What was the C language designer smoking?

Posted by Peeter Joot on June 8, 2010

I regularly see code that grabs the address of the first element in an array in different ways. Some made up examples:

void bar( char * ) ;

void foo
{
   char x[3] ;

   bar( x ) ;
   bar ( &x ) ;
   bar( &x[0] ) ;
   bar( (&x[0]) ) ;
}

Sometimes these get really complex looking when the array element is in some nested structure and the coder in question is so unsure about how to get the first element address that lots of extra braces are tossed in.

It’s worthwhile demonstrating to oneself that these are all identical. Something like the following does the job:

#include <stdio.h>

int main()
{
   char x[3] ;

   printf("%p %p %p\n", x, &x, &x[0] ) ;

   return 0 ;
}

What I have to wonder about something like this is why would the language allow both x and &x as equivalent syntax? Is it so counterintuitive to have x == &x, but this is actually true in this case! Even though I’ve seen it time and time again, the &x syntax seems to be much less common than just x or &x[0], and it throws me off when I see it.

I get the rough impression, at least from our code, that the &x[0] form is generally preferred. I’d infer from this that is it not obvious to many that just plain x is the array base address, and thus the address of the first element.

About these ads

6 Responses to “Address of an array base. What was the C language designer smoking?”

  1. Sam Kendall said

    Not quite. If x is an array, then &x is the address of the entire array, not of the first element. In your example, the compiler should flag bar(&x) as a type mismatch.

    • peeterjoot said

      But that doesn’t change the fact that when one is allowed to use &x, it provides both the address of the array and the first element, and there is not any functional difference. For example:

      #include <stdio.h>
      
      void foo(char * x)
      {
         printf("%p\n", x) ;
      }
      
      void bar(char x[])
      {
         printf("%p\n", x) ;
      }
      
      void barv(void * x)
      {
         printf("%p\n", x) ;
      }
      
      int main()
      {
         char x[3] ;
      
         printf("%p\n", x ) ;
         printf("%p\n", &x ) ;
         printf("%p\n", &x[0] ) ;
      
         foo( x ) ;
         foo( &x[0] ) ;
      
         bar( x ) ;
         bar( &x[0] ) ;
         barv( &x ) ;
      
         return 0 ;
      }
      
      $ ./t
      0x7fff293a7110
      0x7fff293a7110
      0x7fff293a7110
      0x7fff293a7110
      0x7fff293a7110
      0x7fff293a7110
      0x7fff293a7110
      0x7fff293a7110
      
  2. Rein said

    I agree with Sam Kendall.

    Maybe you’ll understand that this ‘inconvenient inconsistency’ is a left over from back in the old days. Until recent object oriented programming came along people put strings in arrays like this:

    char szName[128];
    char szAnotherString[128];

    Then using the ansi c string functions like strcpy would raise an error if you compile:

    strcpy(szAnotherString, szName);

    Because strcpy is defined like

    char *strcpy(
    char *strDestination,
    const char *strSource
    );

    Well ok then, let’s use:

    strcpy(&szAnotherString, &szName);

    Another error arises (by a consistent compiler), you get a pointer to a char[128].

    So this is our best attempt:

    strcpy(&szAnotherString[0], &szName[0]);

    Yes it is! This result in exactly two pointers to a char.
    But this is a very inconvenient way to pass on a string each and every time, so the compiler will convert (all of these) automatically for you.

    Kind regards,
    Rein

    • peeterjoot said

      Rein,

      I can’t produce your claimed compilation error scenerio?

      $ gcc -ansi -c t.c
      $ cat t.c
      #include <stdio.h>
      
      char szName[128];
      char szAnotherString[128];
      
      void foo()
      {
      strcpy(szAnotherString, szName);
      }
      
      • Rein said

        That’s because the compiler automatically converts for you :)

        All of the scenario’s I mentioned would flag as an error with a imaginary compiler that would not convert for you. Don’t know if you can disable these auto conversions, depends on the compiler I guess. You look for a command line switch if you really want to. But I can’t see the point in that anyway.

        Just to clarify once more:

        strcpy(szAnotherString, szName);
        passing on char arguments to a function that accepts only char* arguments -> NOT OK

        strcpy(&szAnotherString, &szName);
        passing on char[128]* arguments to a function that accepts only char* arguments -> NOT OK

        strcpy(&szAnotherString[0], &szName[0]);
        passing on char* arguments to a function that accepts only char* arguments -> OK

  3. hally said

    very easy method to learn.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 38 other followers

%d bloggers like this: