【问题标题】:Undefined length of character arrays字符数组的未定义长度
【发布时间】:2019-07-02 03:20:01
【问题描述】:

我一直在想有什么区别

    char[] = "hello world"

    char[20] = "hello world"

我试着写这个短代码:


    #include <stdio.h>
    #include <stdlib.h>


    int main(){
        int i;
        char str[20] = "hello world";
        for( i = 0; i<20; i++){
            if(str[i]=='\n')
                printf("\nExit character newline");
            else if(str[i]=='\0')
                printf("\nNull terminated..");
            else
                printf("\nCur: %c", str[i]);
        }
        return 0;

    }

哪个输出:


Cur: h
Cur: e
Cur: l
Cur: l
Cur: o
Cur:
Cur: w
Cur: o
Cur: r
Cur: l
Cur: d
Null terminated..
Null terminated..
Null terminated..
Null terminated..
Null terminated..
Null terminated..
Null terminated..
Null terminated..
Null terminated..

另一方面,当我没有专门定义数组大小而只是使用时

    char[] = "hello world"

它给了我这个输出:

Cur: h
Cur: e
Cur: l
Cur: l
Cur: o
Cur:
Cur: w
Cur: o
Cur: r
Cur: l
Cur: d
Null terminated..
Cur: 
Null terminated..
Null terminated..
Null terminated..
Cur: 
Cur:  
Cur: a
Null terminated..

我对上述输出感到困惑。 char[] = "hello world" 不只是以 12 个元素结束,最后一个元素填充了一个空终止符吗?另外,如果我 printf char 和 %s,我的假设是否正确?

【问题讨论】:

  • 您能展示一下您用于char[] 版本的代码吗?
  • 您的循环正在查看 20 个字符,而不是字符串的长度。为什么你认为char[] = "hello world" 和数字 20 之间有任何关系? %s 使用 0 个终止的字符串。如果这就是您所拥有的,printf 将起作用。
  • @John3136 我正在尝试找出并理解在 hello world 中的 'd' 之后可能超出空终止符的内容。我期待 str[] 的其余部分会填充空终止符,就像 str[20] 观察到的一样,所以我只是随机地进行了 20 次迭代。
  • @jdoecs420 数组之后没有什么有趣的。这只是不确定的值。访问它们会导致未定义的行为(google that)。
  • @Jabberwocky 那里可能有一些“有趣”的东西,例如对保持程序的正常执行路径至关重要的其他变量,现在已被覆盖。

标签: c arrays string


【解决方案1】:

声明 `char str[] = "hello world" 为 12 个字符保留空间,最后一个字符为零。与其他一些语言不同。但是,C 实现通常不会捕获越界数组访问。通常,尝试读取超出字符串末尾的内容将访问碰巧跟随它们的任何存储的内容,但除非使用一种允许控制对象放置的实现(例如,通过在翻译单元中只有一个对象,并且使用链接器规范强制将该翻译单元的数据放在另一个翻译单元之前),读取字符串末尾将不会产生可预测的后果。如果一个人正在使用一个积极优化的编译器,它可能会决定它可以省略任何只有当程序试图访问超出数组末尾的数据时才相关的代码。

【讨论】:

    【解决方案2】:

    所以在第一个字符 [20] 中,您可以为最多 20 个字符留出空间,这就是为什么它在最后一个字符之后全部终止的原因。在第二个字符 [] 中,您没有留出额外的空间。因此,似乎正在发生的事情是,当您传递字符串的末尾时,您就是机器其他部分的内存。这就是为什么你会在那里得到随机字符。

    这是另一个更深入的 stackover 流程​​

    How to declare strings in C

    【讨论】:

      【解决方案3】:

      在 c 中,您可以在数组边界之外进行读写。这当然是未定义的行为。但是语言允许。

      当你读取没有为对象分配的内存时,你可能会得到不可预知的值,你也可能会陷入段错误

      【讨论】:

        【解决方案4】:

        我建议你试试这个程序:

        #include <stdio.h>
        #include <string.h>
        
        int main() {
            char str1[] = "hello world";
            char str2[20] = "goodbye world";
            printf("str1: size = %zd, len = %zd\n", sizeof(str1), strlen(str1));
            printf("str2: size = %zd, len = %zd\n", sizeof(str2), strlen(str2));
        }
        

        (如果您有不接受%zd 的旧编译器,您可以改用"size = %d, len = %d\n", (int)sizeof(str1), (int)strlen(str1)。)

        编译器将为您提供您可以认为如下所示的数组:

              +---+---+---+---+---+---+---+---+---+---+---+---+
        str1: | h | e | l | l | o |   | w | o | r | l | d |\0 |
              +---+---+---+---+---+---+---+---+---+---+---+---+
        
              +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
        str2: | g | o | o | d | b | y | e |   | w | o | r | l | d |\0 |   |   |   |   |   |   |
              +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
        

        (实际上,虽然我没有明确显示它们,但可以保证str2 末尾的所有“空”单元格也将包含\0。)

        一般来说,如果你试图从数组的定义端访问内存:(a) 你不会找到任何有趣的东西,并且 (b) 这样做是非法的,尽管 (c) 一个 C编译器通常不会阻止您尝试。

        如果您真的想看看发生了什么,请尝试运行此循环:

        for(int i = 0; i < 30; i++)
            printf("str1[%d] = '%c'\n", i, str1[i]);
        

        您可能会看到字符串“goodbye world”潜伏在str1 的“末尾”内存中。如果没有,请尝试交换str1str2 的顺序:

        char str2[20] = "goodbye world";
        char str1[] = "hello world";
        

        当然,你在这里“打破了规则”,也有可能在这两种情况下你都看不到额外的“再见”字符串,或者你的程序会在尝试中崩溃。

        还有一件事。我想回到你在评论中说的话。你说:

        我正在尝试找出并理解 hello world 中的 'd' 之后的空终止符之外的内容。我原以为str[] 的其余部分会填充空终止符,就像str[20] 观察到的一样。

        现在,事实上,str[20] 的“其余部分填充了空终止符”,具体是因为,只是,因为您显式分配的数组的字符数超过了它所需的字符数。另一方面,当您说str[] = "..." 时,您会得到一个数组,其中恰好 包含它需要的字符(包括以\0 结尾的one)。当你声明str[] = "..." 时,甚至说“剩下的都用...填充”是没有意义的,因为没有“剩余”可以填充。

        【讨论】:

          猜你喜欢
          • 2012-10-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-01
          • 2014-03-15
          • 2013-12-20
          相关资源
          最近更新 更多