如何在 C 中打印出由 char ** 创建的字符串数组?

How do I print out an array of string(array) create by char ** in C?

我是 C 语言的新手,正在尝试使用 char ** 创建数组,但打印出来时遇到问题。有没有办法打印出来,或者我不应该使用这种方式来创建一个字符串数组?

int main()
{
    char **a = {"abc", "ddd", "ccc", "aaa"};

    for (size_t i = 0; i < 4; i++){
        printf("%s\n", a+i);  // only print out "abc" correctly
//        printf("%s\n", *(a+i));  doesn't work
//        printf("%s\n", a[i]);  doesn't work
    }

    return 0;

}

这个声明

char **a = {"abc", "ddd", "ccc", "aaa"};

不正确。标量类型可以仅使用大括号中的单个表达式进行初始化。

如果你想声明一个指针数组,那么你应该写

char * a[] = {"abc", "ddd", "ccc", "aaa"};

要输出它你可以写

for (size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++){
    puts( a[i] );
}

char * a[] = {"abc", "ddd", "ccc", "aaa"};
const size_t N = sizeof( a ) / sizeof( *a );

for (size_t i = 0; i < N; i++){
    puts( a[i] );
}

另一种方法是声明一个 two-dimensional 数组,例如

char a[][4] = {"abc", "ddd", "ccc", "aaa"};

可以按照上面的方式输出。

for (size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++){
    puts( a[i] );
}

如果你想声明char **类型的对象,比如

char **a = /*...*/;

然后你可以用复合文字初始化它。

这是一个演示程序。

#include <stdio.h>

int main(void) 
{
    enum {  N = 4 };
    char **a = ( char * [N] ){"abc", "ddd", "ccc", "aaa"};
    
    for ( size_t i = 0; i < N; i++ )
    {
        puts( a[i] );
    }
    
    return 0;
}

它的输出是

abc
ddd
ccc
aaa

运行 通过编译器发布的代码导致:

gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o" (in directory: /home/richard/Documents/forum)
untitled1.c: In function ‘main’:
untitled1.c:8:17: warning: initialization of ‘char **’ from incompatible pointer type ‘char *’ [-Wincompatible-pointer-types]
    8 |     char **a = {"abc", "ddd", "ccc", "aaa"};
      |                 ^~~~~
untitled1.c:8:17: note: (near initialization for ‘a’)
untitled1.c:8:24: warning: excess elements in scalar initializer
    8 |     char **a = {"abc", "ddd", "ccc", "aaa"};
      |                        ^~~~~
untitled1.c:8:24: note: (near initialization for ‘a’)
untitled1.c:8:31: warning: excess elements in scalar initializer
    8 |     char **a = {"abc", "ddd", "ccc", "aaa"};
      |                               ^~~~~
untitled1.c:8:31: note: (near initialization for ‘a’)
untitled1.c:8:38: warning: excess elements in scalar initializer
    8 |     char **a = {"abc", "ddd", "ccc", "aaa"};
      |                                      ^~~~~
untitled1.c:8:38: note: (near initialization for ‘a’)
untitled1.c:11:18: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]
   11 |         printf("%s\n", a+i);  // only print out "abc" correctly
      |                 ~^     ~~~
      |                  |      |
      |                  char * char **
Compilation finished successfully.

编译时,不要忽略警告。

编译器的最后一行:

 Compilation finished successfully

仅表示编译器对每个问题使用了一些 'workaround',而不是生成了正确的代码。

如果我们进行更改,那么只使用单个指针而不是指向指针的指针:

#include <stdio.h>




int main( void )
{
    char *a = {"abc", "ddd", "ccc", "aaa"};

    for (size_t i = 0; i < 4; i++){
        printf("%s\n", a+i);  // only print out "abc" correctly
//        printf("%s\n", *(a+i));  doesn't work
//        printf("%s\n", a[i]);  doesn't work
    }

    return 0;

}

结果:

gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o" (in directory: /home/richard/Documents/forum)
untitled1.c: In function ‘main’:
untitled1.c:8:23: warning: excess elements in scalar initializer
    8 |     char *a = {"abc", "ddd", "ccc", "aaa"};
      |                       ^~~~~
untitled1.c:8:23: note: (near initialization for ‘a’)
untitled1.c:8:30: warning: excess elements in scalar initializer
    8 |     char *a = {"abc", "ddd", "ccc", "aaa"};
      |                              ^~~~~
untitled1.c:8:30: note: (near initialization for ‘a’)
untitled1.c:8:37: warning: excess elements in scalar initializer
    8 |     char *a = {"abc", "ddd", "ccc", "aaa"};
      |                                     ^~~~~
untitled1.c:8:37: note: (near initialization for ‘a’)
Compilation finished successfully.

哪个更好,但还是不对

修改 a[] 的声明以便正确声明和初始化结果:

char *a[]

读取为指向 char

的指针数组

下一个问题是:

printf("%s\n", a+i);  

这导致:

untitled1.c:17:22: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]

已更正:

printf("%s\n", *(a+i) );

所以一个可以通过但不是很好的代码版本如下所示:

#include <stdio.h>




int main( void )
{
    char *a[] =
    {
        "abc", 
        "ddd",
        "ccc", 
        "aaa"
    };

    for (size_t i = 0; i < 4; i++){
        printf("%s\n", *(a+i) );  // only print out "abc" correctly
//        printf("%s\n", *(a+i));  doesn't work
//        printf("%s\n", a[i]);  doesn't work
    }

    return 0;

}

但是,那有 'magic' 个 4

我们可以通过让编译器执行 for() 循环的计算来消除 'magic' 数字:

for( size_t i = 0; i < (sizeof(a) / sizeof( *a ); i++ )

所以最终的代码是:(删除了多余的空行)

#include <stdio.h>

int main( void )
{
    char *a[] =
    {
        "abc", 
        "ddd",
        "ccc", 
        "aaa"
    };

    for (size_t i = 0; i < (sizeof( a ) / sizeof( *a )); i++)
    {
        printf("%s\n", *(a+i) );  
    }

    return 0;
}

以上代码运行的结果为:

abc
ddd
ccc
aaa