StoneThrow
StoneThrow

Reputation: 6285

Can a temporary array of pointer be passed to a function in C?

In the following code, I'd like to call function f() or f2() with a temporary array of pointers, as lines 33 and 39 ...

#include <stdio.h>

void f( const char** const p, size_t num )
{
  size_t i;
  for ( i = 0; i < num; ++i )
  {
    printf( "%s\n", p[ i ] );
  }
}

void f2( const char* const p[2] )
{
  size_t i;
  for ( i = 0; i < 2; ++i )
  {
    printf( "%s\n", p[ i ] );
  }
}

void withPtrArray()
{
  const char* tmp[] = { "hello", "world" };
  const char** p;

  // This compiles/runs fine:
  f( tmp, sizeof tmp / sizeof( const char* ) );

  // This also compiles/runs fine:
  f( ( p = tmp ), 2 );

  // This does not compile - I'm not clear why.
  f( ( { "hello", "world" } ), 2 );

  // My last hope: I thought a function that explicitly took a pointer array:
  // This works...
  f2( tmp );
  // ...but this does not:
  f2( { "hello", "world" } );
}


void g( const char* const p )
{
  printf( "%s\n", p );
}

// Analog to f2()
void g2( const char p[12] )
{
  printf( "%s\n", p );
}

// These analogs with an array of chars work fine.
void withPtr()
{
  const char tmp[] = "hello world";
  const char* p = tmp;

  g( tmp );

  g( ( p = tmp ) );

  g( ( "hello world" ) );

  g2( tmp );

  g2( "hello world" );
}

int main( int argc, char* argv[] )
{
  withPtrArray();
  withPtr();
  return 0;
}

...but those line fails compilation...

prog.c: In function ‘withPtrArray’:
prog.c:33:17: warning: left-hand operand of comma expression has no effect [-Wunused-value]
   f( ( { "hello", "world" } ), 2 );
                 ^
prog.c:33:27: error: expected ‘;’ before ‘}’ token
   f( ( { "hello", "world" } ), 2 );
                           ^
prog.c:33:6: warning: passing argument 1 of ‘f’ from incompatible pointer type [-Wincompatible-pointer-types]
   f( ( { "hello", "world" } ), 2 );
      ^
prog.c:3:6: note: expected ‘const char ** const’ but argument is of type ‘char *’
 void f( const char** const p, size_t num )
      ^
prog.c:39:7: error: expected expression before ‘{’ token
   f2( { "hello", "world" } );
       ^

It's been a few years since I migrated from C to C++, but I don't believe this is an issue of syntax difference between C and C++.

Is there a C syntax that allows passing a temporary array of pointers to a function?

Upvotes: 1

Views: 345

Answers (1)

M.M
M.M

Reputation: 141638

The problem with f( ( { "hello", "world" } ), 2 ) is this: the arguments to a function must be expressions. However, a braced list of other expressions is not itself an expression.

Maybe you erroneously think of { "hello", "world" } as an expression which perhaps has type "array of 2 char arrays". But that is not true. You may have noticed that { "hello" }; is not valid code either: every expression can be turned into a statement by putting ; after it, therefore {"hello"} can't be an expression.

The following code doesn't work either:

char *c[2];
c = { "hello", "world" };

or even:

int y;
y = { 5 };

In both cases, the assignment operator must be followed by an expression; but there are no expressions whose syntax consists of something inside braces.

A braced list can only occur as the initializer for a declaration, or in a compound literal. The braces indicate that there is a list of initializers present.

The anatomy of a declaration is a typename and declarator, followed by the = symbol (which is NOT the assignment operator, since this is not an expression), followed by an initializer. And an initializer may either be an expression, or a braced list of initializers. The meaning of such a declaration is that each initializer is taken as the initial value for one of the objects being declared in the declaration.


In your code you could use a compound literal:

f( (const char *[2]){ "hello", "world" }, 2 );

The anatomy of the compound literal is that it is syntax for supplying a typename with initializers for an object of that type; it is NOT a cast operator being applied to some sort of expression.

Upvotes: 4

Related Questions