最简单的字符串数组 c 程序上的分段错误(核心已转储)

Segmentation fault(core dumped) on simplest string array c program

我在尝试使用 c 中的字符串时遇到问题。我有这个代码:

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

int main()
{
    char *result[2];
    strcpy(result[0], "String 1");
    strcpy(result[1], "String 2");

    printf("%s\n", result[0]);
    printf("%s\n", result[1]);
}

编译时没有警告,但不会 运行。它说分段错误,执行时核心转储

如何在 C 语言中为字符串数组赋值?

P.D。在此示例中,我尝试分配文字字符串以生成最简单的可重现代码,我知道我可以使用 {"String 1", "String 2"} 或类似的方法直接分配文字字符串,但实际上我需要将变量分配给 result[0]result[1]

的另一个变量

char *result[2]是一个2个指针的数组,它们是未初始化的,如果你想给它们赋值你不能使用strcpy,那个函数将字符串复制到内存位置由这些指针指向,但因为它们未初始化,所以它们不指向任何内存位置。这种构造的行为是未定义的。

如果这些只是为了打印,你可以只使用赋值运算符:

const char *result[2];
result[0] = "String 1";
result[1] = "String 2";

const char *result[2] = {"String 1", "String 2"};

你会注意到我使用了 const,那是因为那些字符串是只读的,你不能更改它们。


如果您想更改它们,您需要通过分配内存或以其他方式使它们指向某个有效的内存位置来初始化指针:

#include <stdlib.h>

char *result[2];

result[0] = malloc(/*length of the string + null byte*/);
result[1] = malloc(/*length of the string + null byte*/);

char str1[/*length of the string + null byte*/];
char str2[/*length of the string + null byte*/];

char *result[2] = {str1, str2};

strcpy(result[0], "String 1");
strcpy(result[1], "String 2");

有了这个,因为你复制了字符串,你现在可以更改它们,它们不再是只读的。


脚注:

  • 实际上默认情况下没有警告,但是在你的编译器中启用额外的警告会警告你,例如 gcc,使用 -Wall 标志将产生以下警告:

    main.c:10:5: warning: 'result[0]' is used uninitialized in this function [-Wuninitialized] 10 | printf("%s\n", result[0]);

  • 你应该总是使用字符数组,i.e char result[2][10] 如果有机会,使用内存在不需要时进行分配对程序来说是不必要的开销。检查这些主题以获取更多信息:

    When and why to use malloc?

    When do I need dynamic memory?

char *result[1];

C 不会自动分配 space 来存储字符串的内容 - 你必须自己做。在这种情况下,您只分配了足够的 space 来存储指针值(即地址)1。因为它是在没有初始化器的情况下声明的,所以该指针值是 indeterminate - 它可以是 0,也可以是 0xdeadbeef,它可以是任何其他值。在这种情况下,不确定的指针值恰好指向可写的内存,因此操作成功。

但是...

由于它不是通过在对象的生命周期内或通过 malloccallocrealloc 调用在对象上使用 & 运算符获得的,因此指针值为 invalid 并且尝试通过无效指针写入的行为未定义。不幸的是,未定义行为的症状之一正在按预期工作——只要你不破坏任何“重要”的东西,你的代码就会正常运行。

char *result[2];

同上处理,虽然这次一个或两个不确定指针值指向不可写的内存,因此运行时错误。

字符串(包括字符串文字)最终存储在数组字符类型中,因此您必须分配足够长的数组来存储整个字符串加上终止符. "String 1" 是 8 个字符长,所以你需要分配一个 至少 9 个字符宽的数组来存储字符串加上终止符:

char result[9];
strcpy( result, "String 1" );

或者如果您的实现支持可变长度数组2,您可以:

size_t len = strlen( "String 1" );
char result[len + 1];
strcpy( result, "String 1" );

或者如果你想动态分配内存:

size_t len = strlen( "String 1" );
char *result = malloc( len + 1 );
if ( result )
  strcpy( result, "String 1" );

如果你想要一个字符串数组,你必须使用一个二维字符数组:

char result[2][9];
strcpy( result[0], "String 1" );
strcpy( result[1], "String 2" );

或指向其他数组或动态内存的 char 指针数组:

char *result[2];

result[0] = malloc( strlen( "String 1" ) + 1 );
result[1] = malloc( strlen( "String 2" ) + 1 );

if ( result[0] )
  strcpy( result[0], "String 1" );

if ( result[1] )
  strcpy( result[1], "String 2" );

  1. 数组不是指针,指针也不是数组。 Array expressions "decay" to pointer expressions as necessary,但它们终究是两种不同的动物。
  2. 尽管名称不同,但可变长度数组的大小不可调整 - 它们的大小在其生命周期内是固定的。 "Variable" 指的是它们的大小可以随定义而变化。