【问题标题】:strcpy() on a string inside a struct - undefined? [duplicate]strcpy() 在结构内的字符串上 - 未定义? [复制]
【发布时间】:2021-01-13 09:49:18
【问题描述】:

我有一个类似于以下定义的结构:

struct csv_headers {
    char field1[256];
    char field2[256];
};

然后在我的代码中,我有:

struct csv_headers fields;
strcpy(fields.field1, str_ary[0]);
strcpy(fields.field2, str_ary[1]);

str_ary[n] 是一些字符串。

这是否会像下面的代码一样导致未定义的行为?

char str[] = "some text";
strcpy(str, "text");

既然 strcpy 不应该用于字符串字面量?

如果是这样,将字符串复制到结构内声明的字符串中的公认方法是什么?我上面的代码示例使用-Wextra 编译时没有警告(假设我输入正确 - 我现在没有代码在我面前)。

我知道使用 strcpy 的潜在危险并且不想在这里讨论,这仅用于说明目的。我只想知道将字符串复制到包含字符串的结构中的公认方式。

【问题讨论】:

  • char str[] = "some text"; strcpy(str, "text"); 有什么问题? str 是一个由 10 个 char 组成的数组,因此您可以将 strcpy 5 char 放入其中。
  • 您不能将单个字符传递给strcpy,所以是的,这是未定义的行为,因为strcpy(fields.field1, str_ary[0]); 没有任何意义并且无法干净地编译。您的问题是为什么不能将char 而不是char* 传递给strcpy
  • 在您的示例中,str 不是字符串文字,它是一个常规的 char 数组,它是 strcpy 的完全有效目标。
  • @Dai 不是。你应该同时使用。
  • 如果str_arychar str_ary[n] 然后strcpy(fields.field1, str_ary[0]); 是错误的,不知道您在尝试什么,但strcpy(fields.field1, &str_ary[0]); 会起作用,而不是您的使用

标签: arrays c string struct


【解决方案1】:

这是否会像下面的代码一样导致未定义的行为?

char str[] = "some text";
strcpy(str, "text");

既然 strcpy 不应该用于字符串字面量?

str 不是字符串文字,它是char[10](通过从字符串文字1复制数据初始化),它是strcpy 的有效目标。此代码确实不会导致未定义的行为;它定义明确且有效。

同样,您的示例中的fields.field1fields.field2 是常规char[]s。在这种情况下,它们是结构的成员并不重要。

但是,请确保 source 有效:str_ary[0] 看起来很可疑,除非 str_ary以零结尾的字符串数组,即类似于 @ 987654330@.


1 从一个字符串字面量初始化一个字符串数组就像strcpy 一样发生,即它几乎与写入完全相同

char str[sizeof("some text")];
strcpy(str, "some text");

事实上,编译器可以(至少在某些情况下)为这个初始化生成与直接赋值相同的代码。相比之下,char *str = "some text"; 不执行复制,这里str 是一个指向字符串文字的指针,因此是只读的,而不是strcpy 的有效目标。

【讨论】:

  • 谢谢,str_ary 确实是一个以零结尾的字符串数组。
【解决方案2】:

这是否会像下面的代码一样导致未定义的行为?

嗯,你的 sn-p 不会引起问题。

char str1[] = "foo"; // str1 is a regular array initialized to "foo"
char *str2 = "bar"   // str2 is a pointer, pointing to a string literal
strcpy(str1, "FOO"); // Ok
strcpy(str2, "BAR"); // Undefined behavior

【讨论】:

    【解决方案3】:

    只要字符串适合目标空间,甚至

    char str[] = "some text";
    strcpy(str, "text");
    

    定义明确。

    char field1[256]; 声明一个可容纳 256 个字符的数组。这允许您存储最多 255 个字符的以 null 结尾的字符串(数组大小,为 null 终止符减一)。

    char str[256] = "some text"; 额外初始化数组以包​​含字符串"some text"。您仍然可以将最多 255 个字符的字符串复制到数组中,因为这就是空间的大小。

    char str[] = "some text";char str[10] = "some text"; 完全相同。使用空括号,str 仍然是一个字符数组。空括号的意思是数组的大小(通常会放在括号内)是自动确定的。与带有大小的括号相比,没有其他区别。对于字符数组,大小是字符串的长度加上空终止符的长度。

    在所有涉及数组的情况下,用于初始化数组的字符串(如果有的话)都存储在数组本身中。它不能以任何其他方式访问,如果您更改数组,则用于初始化它的字符串不再存在于内存中(至少在无法找到它的意义上 - 无法保证它不会出现在内存转储中,但您无法从程序中访问它)。

    关键的区别不在char str[10]char str[] 之间,而是在char str[…]char *p 之间。使用* 而不是括号,char *p 声明一个指针,而不是一个数组。

    char *p = "some text";
    

    做两件事。一件事是它安排将字符串文字"some text" 存储在程序的整个持续时间都可以访问的某个地方。另一件事是它声明了一个变量p,它指向这个字符串文字。您不能修改存储"some text" 的内存(实际上,在许多平台上,它位于只读内存中)。另一方面,您可以让其他内容指向该内存,您可以更改p 以指向其他内容。

    char *p = "some text";
    char *q;
    puts(p); // prints "some text"
    q = p;
    p = "hello";
    puts(q); // prints "some text"
    puts(p); '// prints "hello"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 1970-01-01
      • 2020-02-17
      相关资源
      最近更新 更多