【问题标题】:C - Static char array vs dynamic char arrayC - 静态字符数组与动态字符数组
【发布时间】:2025-12-16 07:45:01
【问题描述】:

此代码编译时会出现警告,但会打印输入字符串:

char staticArray[100];
scanf("%s",&staticArray);
printf("%s\n", staticArray);

警告:格式指定类型“char *”,但参数的类型为“char (*)[100]”[-Wformat]

此代码编译时也会出现警告,但会引发分段错误:

char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", &dynamicArray);
printf("%s\n", dynamicArray);

警告:格式指定类型“char *”,但参数的类型为“char **”[-Wformat]

我知道两者都是错误的,但是为什么第一个打印字符串值?

【问题讨论】:

  • 对于第二个示例中的警告,问题是您获得的指针 dynamicArray 已经是一个指针。删除 & 将修复警告。
  • 警告是因为您将错误的类型传递给scanf。它想要一个char *,但你却传递了一个char (*)[100]。正如它告诉你的那样。通过删除& 来修复它,即scanf("%s", staticArray); 请记住,C 数组在许多上下文中“衰减”为指针,包括作为函数参数传递。

标签: c arrays string dynamic static


【解决方案1】:

删除两个示例中的 & 运算符将解决警告。我不确定您的预期行为是什么,但在移动 & 运算符时它们似乎可以正常工作。这是因为数组本质上是指向数组第一个元素的指针,所以添加 & 不是您想要的。

工作示例(与 & 完全相同):

char staticArray[100];
scanf("%s",staticArray);
printf("%s\n", staticArray);

char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", dynamicArray);
printf("%s\n", dynamicArray);

【讨论】:

  • 谢谢,我知道在没有 & 运算符的情况下它可以正常工作。在将指针传递给静态数组时,我要求不同的行为。我期待一个分段错误,但它打印了一些值。 HS答案解释了原因。
【解决方案2】:

为什么第一个打印字符串值,而第二个给出段错误?

案例一发生了什么:

staticArray 的类型是char [100],即100char 的数组。
&staticArray 的类型是 char (*)[100]
scanf() 中的 %s 格式说明符期望参数是指向 char 数组的初始元素的指针,即 char * 类型。

您将char (*)[100] 类型传递给scanf(),因此编译器会对此语句发出警告。

&staticArray 为您提供指向 char (*)[100] 类型数组的指针,它在数值上与数组的基地址相同。

考虑这个例子:

#include <stdio.h>

int main(void)
{
    char staticArray[100];

    printf ("staticArray: %p\n", (void*)staticArray);
    printf ("&staticArray : %p\n", (void*)&staticArray);

    return 0;
}

输出:

## ./a.out
staticArray: 0x7ffee4044a70
&staticArray : 0x7ffee4044a70

staticArray&amp;staticArray 都产生指向相同地址的指针1),但它们的类型不同。 这就是为什么当您将&amp;staticArray 传递给scanf() 时,由于类型不匹配而在编译期间收到警告,但是当调用scanf() 时,它将该指针视为char * 并读取输入并将结果存储到给定位置。稍后打印时,它会打印字符串值。

案例二发生了什么:

dynamicArray 的类型是char *
&amp;dynamicArray 的类型是 char **
因此,您将char ** 类型传递给scanf(),当使用%s 格式说明符时,它需要char *。因此编译器对此语句发出警告。 指针&amp;dynamicArraydynamicArray 不同。

考虑这个例子:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char* dynamicArray;
    dynamicArray = malloc(sizeof(char)*100);
    if (dynamicArray == NULL) {
        exit(EXIT_FAILURE);
    }

    printf ("dynamicArray: %p\n", (void*)dynamicArray);
    printf ("&dynamicArray : %p\n", (void*)&dynamicArray);

    free(dynamicArray);
    return 0;
}

输出:

## ./a.out
dynamicArray: 0x7fd615401690
&dynamicArray : 0x7ffee7ab7ad0

dynamicArray&amp;dynamicArray产生不同的指针

当您将&amp;dynamicArray 传递给scanf()读取输入并将结果存储到给定位置)时,会导致未定义的行为2),因为您的程序最终访问无效内存。

当您使用格式说明符%sprintf()&amp;dynamicArray 传递给printf() 时,它访问该地址以写入字符串并最终访问无效内存,导致未定义的行为2)。因此,您遇到了段错误。


1) 数组会自动转换为指向其第一个元素的指针,但此规则很少有例外(C11 标准#6.3.2.1p3):

  • 数组是sizeof运算符的操作数。
  • 数组是_Alignof运算符的操作数。
  • 数组是&amp;的操作数。
  • 数组是用于初始化数组的字符串字面量。

2) 一个undefined behavior 包含它可能执行不正确(崩溃或静默生成不正确的结果),或者它可能偶然地完全按照程序员的意图执行。

【讨论】: