【问题标题】:Appending a char w/ null terminator in C在 C 中附加一个带有空终止符的字符
【发布时间】:2016-01-13 06:54:30
【问题描述】:

也许有点微不足道,但我刚刚学习 C,我讨厌用 2 行代码来做,用一行代码可以做什么(当然只要它不会混淆代码)。

无论如何,我通过一次附加一个字符来构建字符串。我通过跟踪正在构建的字符串的字符索引以及输入文件字符串的(行)索引来做到这一点。

str[strIndex] = inStr[index];
str[strIndex + 1] = '\0';

str 用于临时存储输入行中的单词之一。 每次添加字符时,我都需要附加终止符。

我猜我想知道什么;有没有办法将这些组合在一个语句中,而不使用 strcat()(或每次我开始一个新单词时用 memset() 清除 str)或创建其他变量?

【问题讨论】:

  • 您不必每次都附加空字符。只需将其附加到字符串的末尾即可。有多少根弦?你能进一步解释一下吗?
  • 您可以在循环的末尾添加它。表示循环外的第一行。
  • 我已经在下面发布了答案。如果您认为可以,请将其标记为已接受。
  • 但是如果这只需要做一次,例如在 lop 之外,它仍然引出了一个问题,这两个语句可以合并为一个吗?我想我问的是有没有一种方法可以在不使用库函数的情况下一次附加 2 个(或更多)字符?
  • 如果您正在谈论为数组的多个索引分配多个值,而没有库函数,据我所知,这是不可能的。

标签: c arrays null char append


【解决方案1】:

简单的解决方案:在添加任何内容之前将字符串清零。 NULs 将提前到达每个位置。

// On the stack:
char str[STRLEN] = {0};

// On the heap
char *str = calloc(STRLEN, sizeof(*str));

calloc 的情况下,对于大型分配,您甚至无需支付显式清零内存的成本(在批量分配模式下,它直接从操作系统请求内存,这要么是惰性清零(Linux ) 或在您请求之前已将背景归零 (Windows))。

显然,您甚至可以通过推迟字符串的 NUL 终止直到您完成构建它来避免这种工作量,但如果您可能需要随时将其用作 C 风格的字符串,保证总是NUL-预先终止并不是不合理的。

【讨论】:

    【解决方案2】:

    我相信你现在的做法是最能满足你要求的

    1) 没有以全零开头的字符串

    2) 在每个阶段,字符串都是有效的(因为总是有一个终止符)。

    基本上你想每次添加两个字节。真正做到这一点的最巧妙的方式就是你现在的方式。

    如果您想通过“一行”而不是调用函数来使代码看起来更整洁,那么也许是一个宏:

    #define SetCharAndNull( String, Index, Character )  \
    {                                                   \
        String[Index] = (Character);                    \
        String[Index+1] = 0;                            \
    }
    

    并像这样使用它:

    SetCharAndNull( str, strIndex, inStr[index]);
    

    否则,在大多数情况下,我能想到的唯一其他可以实现结果的就是一次写一个“单词”(两个字节,所以是unsigned short)。你可以用一些可怕的类型转换和指针算法来做到这一点。我强烈建议不要这样做,因为它的可读性不是很好,而且它也不是很便携。它必须针对特定的字节顺序编写,而且在需要对齐单词访问的系统上也会出现问题。

    [编辑:添加以下内容] 为了完整起见,我在这里提出了我提到的那个糟糕的解决方案:

    *((unsigned short*)&str[strIndex]) = (unsigned short)(inStr[index]);
    

    这是将str[strIndex] 的指针类型转换为unsigned short,在我的系统(OSX)上是16 位(两个字节)。然后将值设置为 inStr[index] 的 16 位版本,其中前 8 位为零。因为我的系统是小端的,所以第一个字节将包含最低有效的一个(即字符),第二个字节将是单词顶部的零。但正如我所说,不要这样做!它不适用于大端系统(您必须添加左移 8),这也会导致某些处理器上出现对齐问题,您无法访问非 16 位对齐地址上的 16 位值(这将使用 8 位对齐设置地址)

    【讨论】:

    • 假设您可以使用 C99 或更高版本并获得适当的内联语义,我会在预处理器宏上使用 inline 函数;它使您的类型安全,并允许调试器在使用符号编译时更好地工作。您没有使用宏独有的任何功能(例如检查__LINE__,引用未显式传递的作用域变量),因此inline 函数应该同样有效(有时更是如此,因为编译器对正在发生的事情有更多的了解用于优化)。
    • 示例:static inline void set_char_and_null(char *str, size_t idx, char val) { str[idx] = val; str[idx+1] = '\0'; }
    【解决方案3】:

    声明一个字符数组:

    char str[100];
    

    或者,

    char * str = (char *)malloc(100 * sizeof(char));
    

    将所有字符一个一个循环添加:

    for(i = 0; i<length; i++){
        str[i] = inStr[index];
    }
    

    以空字符结束(循环外):

    str[i] = '\0';
    

    【讨论】:

    • 但是如果这只需要做一次,例如在循环之外,它仍然引出了一个问题,这两个语句可以合并为一个吗?我想我问的是有没有一种方法可以在不使用库函数的情况下一次附加 2 个(或更多)字符?
    【解决方案4】:

    首先,C 没有字符串,只有字符数组。因此,如果您不想使用其他辅助功能,则必须像您正在做的那样一个一个地分配每个字符。但是 \0 字符只出现在字符数组的末尾。

    【讨论】:

      猜你喜欢
      • 2017-04-15
      • 2012-01-02
      • 2021-06-12
      • 1970-01-01
      • 2020-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多