【问题标题】:Changing an element of an array of char[]更改 char[] 数组的元素
【发布时间】:2021-01-05 22:53:05
【问题描述】:

我发现 C 中的字符串或字符数组令人困惑,因此我在编写代码时往往会犯错误。下面的代码接受一个字符数组,并在打印时将第四个元素打印为 x

void printString(char stuff[]) {
    for (int i = 0; i < 5; i++) {
        if (i == 3) {
            stuff[i] = 'x';
        }
        printf("%c", stuff[i]);
    }
}

int main(void) {
    char z[] = "hello";
    printString(z); // output helxo

当尝试将相同的概念应用于字符数组数组时,您无法更改值

void printStrings(char stuff[5][20]) {
    for (int i = 0; i < 5; i++) {
        if (i == 4) {
            stuff[i] = "Not Cool"; // Error: assignment to expression with array type
        }
        printf("%s\n", stuff[i]);
    }
}

int main(void) {
    char a[5][20] = {
        "Words",
        "More Words",
        "Letters",
        "Arrays",
        "Cool"
    }
}

任何帮助将不胜感激。

附注任何指向解释字符数组和字符串的资源的链接也会有所帮助:)

【问题讨论】:

    标签: arrays c string char


    【解决方案1】:

    = 运算符未定义为将一个数组的内容复制到另一个数组。您要么必须在循环中单独复制每个数组元素:

    for ( size_t i = 0; i < num_elements; i++ )
      dst[i] = src[i];
    

    或者您必须调用像 strcpy(对于包含字符串的数组)或 memcpy(对于不包含字符串的数组)这样的库函数,它们在底层做的事情几乎相同。

    structunion 等其他聚合类型相比,C 中的数组和数组表达式很奇怪;作为这种怪异的一部分,数组表达式不允许成为赋值运算符的目标。在大多数情况下,“T 的数组”类型的表达式被转换或“衰减”为“指向T 的指针”类型的表达式,表达式的值是第一个元素的地址数组。

    这不是任意的 - Ritchie 有理由让数组以这种方式运行 - 但这并没有让它变得不那么奇怪。

    【讨论】:

      【解决方案2】:

      当尝试将相同的概念应用于字符数组数组时,您无法更改值

      是的,你可以,只是不是你现在做的那样。您不能将一个数组分配给另一个数组。但是您可以使用strcpy() 代替将一个数组中的字符复制 到另一个数组,例如:

      strcpy(stuff[i], "Not Cool");

      或者更好,strncpy(),例如:

      strncpy(stuff[i], "Not Cool", 20);

      【讨论】:

      • 在这里使用strncpy 有什么意义?要么缓冲区足够长,那么strcpy 就可以了,或者缓冲区不够长,在这种情况下,字符串将被部分复制,而复制的字符串没有 NUL 终止符,这几乎不比缓冲区溢出好。
      • @Jabberwocky 如果需要,您始终可以强制使用空终止符:strncpy(stuff[i], "Not Cool", 20); stuff[i][19] = '\0'; 或者,您可以简单地告诉 printf() 不要依赖空终止符:printf("%.20s\n", stuff[i]);
      • @RemyLebeau,如果您依赖完全复制的字符串,则对部分复制的字符串强制零终止可能会导致一类新的错误。这些错误可能比错过零终止或缓冲区溢出更难发现。
      • @HAL9000 好吧,如果您依赖大于缓冲区的字符串,那么您无论如何都会遇到其他问题。
      • @RemyLebeau,我的意思是通过添加零终止来“修复”部分复制的字符串,只是隐藏了问题。它不能解决任何问题。如果程序无法正确处理它,最好打电话给abort。但这已经过时了,所以我要退出了
      【解决方案3】:

      当尝试将相同的概念应用于字符数组数组时,您无法更改值

      问题不在于您无法更改这些值。正如编译器告诉你的那样:你不能分配给整个数组。

      鉴于此声明:

      void printStrings(char stuff[5][20]) {
      

      参数stuff是一个指向20个chars数组的指针。 stuff[4] 因此指定一个数组,而不是左值——你不能分配给它。但是您可以通过赋值修改其元素,或者更一般地说,您可以通过适当的函数修改其内容,例如strcpy()

          stuff[4][0] = 'f';
      

      我发现 C 中的字符串或字符数组令人困惑

      关于 C 字符串有一些令人困惑的事情,但我希望对您有所帮助的一件事是认识到字符串和字符数组不是一回事。字符串是可以由字符数组的内容表示的值。即使一个字符数组包含一个字符串(因为它的任何一个或多个元素具有值 '\0' 并因此用作字符串终止符),数组本身也不是字符串,即使我们有时对我们的语言有点松懈围绕这些东西。

      再加上字符串文字有自己的怪癖,而数组通常也有怪癖,是的,有很大的混淆空间。

      【讨论】:

        【解决方案4】:

        您的误解源于您认为数组是可分配的,其他对象也是如此。数组的C概念有点差。当您将数组标识符作为一个整体使用时,您所指的并不是整个数组,而只是它的第一个元素的(恒定)地址(如指针),因此您不能写如下内容:

        char A[100], B[100];
        A = B; /* error, A is a constant address (the address of A array) and B is a constant address, so A is not assignable. */
        

        这在将数组作为参数传递给函数时非常有效,因为它避免了将整个数组复制到参数列表中,而只是在其中放入了一个指针。它还让最初的 C 实现者可以在分配数组时编写代码来复制完整的内存块(这在编程中很少使用)

        为了提供解决方案,他们编写了一系列函数,允许您复制数组或字符串(它们是 char 的数组)。您可以使用:

        #include <string.h>
        ...
               strcpy(stuff[i], "Not cool");
        

        这将使字符串文字被复制到i-esim 数组元素的位置。

        你说过

        当尝试将相同的概念应用于字符数组数组时,您无法更改值

        但在第一种情况下,当您切换到数组时,您分配了一个 char 对象(作为标量值在 C 中可分配),您会发现整个数组在 C 中不可分配。

        【讨论】:

          猜你喜欢
          • 2016-08-08
          • 2019-05-10
          • 2011-08-22
          • 1970-01-01
          • 2015-07-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多