char **s和char *s[]有什么区别?何时以及如何使用它们?

6
如果我使用字符*s[],我可以做到以下几点:
char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

char **schar *s[]有什么不同?在这种情况下,我如何使用char **s而不是char *s[]

例如:int main(int argc, char **argv)而不是*argv[]


Marcelo,如果问题得到了解决,请不要忘记将一个答案标记为已接受的答案。或者请进一步澄清问题。 - sidyll
9个回答

7

对于函数参数,没有任何区别。

否则:

char *s[];

s是一个指向char类型的指针数组。

char **s;

s是指向指向字符的指针。

如果您需要一个指向字符指针的数组,则使用前者;如果您需要一个指向指向字符的指针的指针,则使用后者。


4
作为函数参数,它们没有任何区别。它们是等效的。
void f(int** p);
void f(int* p[]);
void f(int* p[42]);

这三个声明是等价的。 作为对象,它们有不同的类型;
char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};

s 是一个指向 char 类型的指针数组,包含 6 个指针。 sizeof(s) == 6*sizeof(void*)


char **s;

s是指向指针的指针,sizeof(s) == sizeof(void*)

(说明:s是一个指向char类型指针的指针,且它所占的内存大小与void*类型相同。)

使用 sizeof(char *) 而不是 void * - tomlogic
1
@tomlogic:我使用void*来强调所有指针具有相同的大小,并且一个是指针,另一个是指针数组(无论指向什么)。 - Armen Tsirunyan
@Armen:不完全正确:https://dev59.com/_XM_5IYBdhLWcg3ww2AQ。然而,`char *void *`具有相同的大小和表示形式。 - Alok Singhal

1

数组和指针是不同的东西。指针可以用来访问数组中的元素。要初始化一个数组,你需要声明一个数组,而不是一个指针。

为了清楚地展示这种差异,请尝试以下操作:

int[] ia = {1, 2, 3, 4, 5, 6, 7, 8};
int* ip = ia;

printf("sizeof(ia): %zu, sizeof(ip): %zu", sizeof(ia), sizeof(ip));

第一个应该打印数组的大小,第二个应该打印 int 指针的大小。

C 语言中奇怪的是,当数组作为参数传递给函数时,它会转换成指针。详见 http://www.lysator.liu.se/c/c-faq/c-2.html 第 2.3 节。主函数接受 argv** 而不是 argv*[] 的原因是当作为函数参数传递时,argv*[] 会转换成 argv**


1

这不是直接回答你的问题,但可能会帮助你更好地理解:

#include <stdio.h>
#include <string.h>

int main() {

    char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

    printf("  s[0]: %s \n", s[0]);
    printf("    *s: %s \n", *s);
    printf("  *s+1: %s \n", *s+1);
    printf("*(s+1): %s \n", *(s+1));

return 0;
}

输出:

$ gcc -o chararr chararr.c 
$ ./chararr 
  s[0]: foo   
    *s: foo 
  *s+1: oo 
*(s+1): bar 

1

它们创建相同的数据结构。唯一的区别是char*s[]在初始化时自动为{"foo", "bar", "foobar", "whatever", "john, "doe"}分配足够的内存。而char **s只会为指针分配一个字节,然后您需要手动为数组中的每个字符串分配内存。


0

如果你定义了

char **s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};

我认为这与定义三维数组(char s[10][10][10])相同,因为char *s[]定义了一个二维数组。


0

这取决于您的需求。如果您的程序不需要稍后修改这些字符串,您可以使用

char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

这些被编译为只读区域中的字符串字面量。

汇编输出:

        .file   "test.c"
        .section        .rodata
.LC0:
        .string "foo"
.LC1:
        .string "bar"
.LC2:
        .string "foobar"
.LC3:
        .string "whatever"
.LC4:
        .string "john"
.LC5:
        .string "doe"
        .text

如果您尝试在程序中稍后修改这些字符串,您将会得到一个分段错误。在这种情况下,您必须使用char **s


如何使用char **s分配(即6)个单词? - Marcelo Araujo

0
据我所知,**s是s地址的地址,而*s[]是数组s的地址,我认为你会在s中存储单个值,但在s[]中你会存储数组,而数组本身就是一个指针。希望这可以帮到你!

嗯,对于双指针,你可以存储单个值,但更有可能是一块数据或指向块的指针块。 - alternative
我的意思是它指向数组,而不是数组就是指针,我在那一点上搞错了。 - Grigor

0
当您使用char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};时,编译器已经知道数组的长度,即在这种情况下,它知道它是指向6个字符数组的指针。 char **缺乏长度信息,这正是为什么main有2个参数{length, pointer to pointer to char} == {argc, arv}的原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接