C *arr[]和**arr之间的差异

C *arr[]和**arr之间的差异,c,C,都一样 char* s1[size]; 到 它们有什么区别吗?几乎没有区别: s1不是左值,因此不能修改,例如使用赋值或增量运算符。因此,它类似于char**const s1类型,该类型也不允许修改,但在本例中,这是由const修饰符引起的。 用于数组地址的运算符&将返回数组地址,即第一个元素的地址。在变量上使用&时,它将返回其地址: assert((void*)&s1 == (void*)s1); assert((void*)&s2 != (void*)s2); 数组上使用

都一样

char* s1[size];


它们有什么区别吗?

几乎没有区别:

s1不是左值,因此不能修改,例如使用赋值或增量运算符。因此,它类似于char**const s1类型,该类型也不允许修改,但在本例中,这是由const修饰符引起的。 用于数组地址的运算符&将返回数组地址,即第一个元素的地址。在变量上使用&时,它将返回其地址:

assert((void*)&s1 == (void*)s1);
assert((void*)&s2 != (void*)s2);
数组上使用的sizeof将返回数组大小,而指针上使用的sizeof将返回指针大小-通常与sizeofvoid*相同,但C标准不要求此值,请参见下面的注释:

assert(sizeof(s1) == size * sizeof(char*));
assert(sizeof(s1) == size * sizeof(s1[0])); // this is the same
assert(sizeof(s2) == sizeof(void*)); // on some platforms this may fail
当然,很明显,s1在堆栈上分配,s2在堆上分配。因此,当执行离开当前作用域时,s1将自动销毁,s2需要调用free来释放内存

更新:以下是检查上述断言的示例代码:

#include <assert.h>
#include <stdlib.h>

int main()
{
    const int size = 22;

    char* s1[size];
    char** s2 = (char**)malloc(size * sizeof(char*));

    assert((void*)&s1 == (void*)s1);
    assert((void*)&s2 != (void*)s2);

    assert(sizeof(s1) == size * sizeof(char*));
    assert(sizeof(s1) == size * sizeof(s1[0])); // this is the same
    assert(sizeof(s2) == sizeof(void*)); // on some platforms this may fail

    free(s2);

    // Attempts to modify value
    char** const s3 = s1;
    ++s2; 
    //++s1; // compilation error - lvalue required as increment operand
    //++s3; // compilation error - increment of read-only variable ‘s3’

    return 0;
}
理论上,*arr[]和**arr是不同的。例如:

char *arr[size]; //case 1
这里,arr是一个大小为的数组,其元素的类型为char*

鉴于

char **arr; //case2
这里,arr本身就是指向char类型的指针*

注意:在案例1中,数组arr降级为指针以成为char**类型,但不可能反过来,即案例2中的指针不能成为数组

是在堆栈上分配的char类型的指针数组

char** s2 = malloc(size * sizeof(char*));
是在堆栈上分配的char**类型指针,但指向在堆上分配的char*类型指针的动态数组

这两种方法的作用域不同,数组和指针之间通常也有区别。

s1是数组,s2是指针。s2指向malloced数组的第一个元素

数组s1具有自动存储持续时间,而s2指向的数组具有动态存储持续时间


此外,在C89字符*s1[大小]中;仅当大小为常量表达式时才有效,因为C89不支持可变长度数组。

是,如果对其使用sizeof或_Alignof,或使用地址&。它们可以使用相同的值,但第一个值具有自动存储持续时间,而第二个值没有。还有一种情况,第一种可以使用,而第二种不能使用。@Kupiakos:胡说,它们是不同类型的,而且不一样!与arr[]和*arr@Olaf更准确地说,它们可以在许多情况下使用相同的方法。您的断言中的相等运算符是违反约束的。这是完全错误的!数组不是指针也不是数组。啊,我忘了将指针强制转换为void*。我更正了这一点,并用这些断言添加了示例代码。您声称*arr[]类型等同于**const ptr类型的说法仍然是错误的。您将在C11标准草案n1570、6.3转换、6.3.2.1左值、数组和函数指示符中找到一些有用的阅读资料。请注意,指向void的指针的大小不一定与sizeofchar**相同。C标准仅对指向字符N1570 6.2.5/28的指针做出了此类规定:指向void的指针应与指向字符类型的指针具有相同的表示和对齐要求。。其他指针的类型可以是任意大小:指向其他类型的指针不需要具有相同的表示或对齐要求。。
char* s1[size];
char** s2 = malloc(size * sizeof(char*));