【问题标题】:How to append to array in C如何在C中追加到数组
【发布时间】:2021-08-20 20:39:20
【问题描述】:

假设我有一个将用字符串填充的空数组,那么当我需要时如何向它附加一个字符串?

这是我目前所拥有的

string people[20] = {};

string name = "james";

strcpy(people[0], name);

【问题讨论】:

  • 使用strcat 附加到现有的以空字符结尾的字符串的末尾。
  • 另外,您需要为people[0] 分配空间,然后才能对其进行存储。请记住,cs50 中的 string 只不过是 char * 中的 typedef

标签: arrays c append c-strings


【解决方案1】:

CS50 再次来袭。

请注意,在使 C 更易于使用的过程中,CS50 库严重歪曲了字符串和字符串处理在 C 中的实际工作方式。string 类型不是原生 C 类型- 它是类型“指向char”(char *)的类型定义名称(别名)。 CS50 string 实际上并不存储 string(字符序列),它存储的是字符串第一个字符的 address。这意味着

string people[20];

实际上并不是一个字符串的数组,它是一个指针的数组:

char *people[20];

在 C 中,字符串是包含 0 值终止符的字符值序列 - 字符串 "hello" 表示为序列 {'h', 'e', 'l', 'l', 'o', 0}。所有字符串(包括字符串文字)都存储为字符类型的数组char 用于 ASCII/EBCDIC/UTF-8,wchar_t 用于“宽”编码)。

在大多数情况下,数组表达式“衰减”为指针表达式1,所以大多数时候当我们处理字符串时,我们都在处理指针表达式,但指针不是字符串.

如果要将多个字符串一起追加成一个字符串,比如

"foo" + "bar" == "foobar"

那么您需要执行以下操作:

/**
 * Create a target buffer large enough to store the final string. In
 * this case we need a buffer 7 elements wide - 6 for the characters
 * "foobar" plus 1 for the string terminator.  The initial contents of
 * this array are *indeterminate*:
 *
 * +---+---+---+---+---+---+---+
 * | ? | ? | ? | ? | ? | ? | ? |
 * +---+---+---+---+---+---+---+
 */
char target[7]; 

/**
 * Copy the string "foo" to the target buffer.  After this operation,
 * the target buffer will contain:
 *
 * +---+---+---+---+---+---+---+
 * |'f'|'o'|'o'| 0 | ? | ? | ? |
 * +---+---+---+---+---+---+---+
 */
strcpy( target, "foo" ); 

/**
 * Append "bar" to the end of the string in target - looks for the 
 * string terminator, and starts appending at that point.  After 
 * this operation the target array should contain:
 *
 * +---+---+---+---+---+---+---+
 * |'f'|'o'|'o'|'b'|'a'|'r'| 0 |
 * +---+---+---+---+---+---+---+
 */
strcat( target, "bar" ); 

如果您想创建一个 array 字符串(这就是您所要求的),那么您将需要创建一个 char 的二维数组:

char strings[NUM_STRINGS][MAX_STRING_LENGTH+1];

然后使用strcpy复制字符串内容:

strcpy( strings[0], "foo" );
strcpy( strings[1], "bar" );
strcpy( strings[2], "bletch" );

给你类似的东西

           +---+---+---+---+---+---+---+     +---+
strings[0] |'f'|'o'|'o'| 0 | ? | ? | ? | ... | ? |
           +---+---+---+---+---+---+---+     +---+
strings[1] |'b'|'a'|'r'| 0 | ? | ? | ? | ... | ? |
           +---+---+---+---+---+---+---+     +---+
strings[2] |'b'|'l'|'e'|'t'|'c'|'h'| 0 | ... | ? |
           +---+---+---+---+---+---+---+     +---+

或者您将需要创建一个指针数组(这是您在代码中拥有的),然后存储每个字符串的地址

char *strings[NUM_STRINGS];

strings[0] = "foo";
strings[1] = "bar";
strings[2] = "bletch";

这给了你类似的东西

            +---+                               +---+
strings[0]: |   | ----------------------------> |'f'|
            +---+                      +---+    +---+
strings[1]: |   | -------------------> |'b'|    |'o'|
            +---+             +---+    +---+    +---+
strings[2]: |   | ----------> |'b'|    |'a'|    |'o'|
            +---+             +---+    +---+    +---+
             ...              |'l'|    |'r'|    | 0 |
                              +---+    +---+    +---+
                              |'e'|    | 0 |     ...
                              +---+    +---+
                              |'t'|     ...
                              +---+
                              |'c'|
                              +---+
                              |'h'|
                              +---+
                              | 0 |
                              +---+
                               ...

请注意,字符串文字可能不可写 - 尝试修改字符串文字内容的行为是未定义。您的代码可能崩溃,它可能会按预期运行,它可能会损坏其他数据,或者它可能会完全执行其他操作。如果你有类似的东西

char *strings[20];
...
strings[0] = "joe";

然后你可以设置strings[0] 指向不同的字符串字面量,像这样:

strings[0] = "bob";

但是如果你尝试修改strings[0]指向的文字的内容

strcpy( strings[0], "bob" );

那么您的代码可能无法按预期运行。但是,如果您创建一个数组并使用字符串对其进行初始化:

char *strings[20];
char name[] = "joe";

strings[0] = name; // assigning the *address* of name[0] to strings[0]
strcpy( strings[0], "bob" );

那么这将按预期工作,因为strings[0] 指向name,这是一个可写缓冲区。但是name 最多只能存储 3 个字符的名称,所以如果你尝试做类似的事情

strcpy( strings[0], "aloysius" );

您将写到 names 数组的末尾并破坏它后面的任何内容。

是的,C 中的字符串处理是主要的 PITA,这就是 CS50 库试图掩盖它的原因。但同样,在这样做的过程中,他们歪曲了事情的实际运作方式,并且在学生必须自己处理 C 字符串时让他们陷入失败。


  1. 除非它是sizeof 或一元& 运算符的操作数,或者是用于在声明中初始化字符类型数组的字符串文字,否则为表达式 “T 的 N 元素数组”类型的 em> 将被转换或“衰减”为“指向 T 的指针”类型的表达式,表达式的值将是第一个元素的地址数组。

【讨论】:

    【解决方案2】:

    考虑到您的代码 sn-p

    string people[20] = {};
    
    string name = "james";
    
    strcpy(people[0], name);
    

    似乎string 类型的定义如下

    typedef char * string;
    

    所以这个声明

    string people[20] = {};
    

    声明char *类型的元素数组。

    您不能将空大括号用作初始化程序。你至少需要写像

    string people[20] = { NULL };
    

    所以要向数组中添加一个元素,你应该写

    people[0] = name;
    

    或者不使用中间变量

    people[0] = "james"; 
    

    另一种方法是为数组的元素动态分配内存并在内存中复制一个字符串。例如

    people[0] = malloc( strlen( name ) + 1 );
    strcpy( people[0], name );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-04
      • 1970-01-01
      • 2014-05-16
      • 2019-05-13
      • 1970-01-01
      相关资源
      最近更新 更多