【问题标题】:Can I use values of array declared as local variable outside of its scope?我可以在其范围之外使用声明为局部变量的数组值吗?
【发布时间】:2015-04-12 18:36:23
【问题描述】:

假设以下简单代码:

int main(void){
  char *p;
  int i = 1;
  while(i){
    char str[] = "string";
    p = str;
    i = 0;
  }
  /* Can I use above string by using `p` in here? */
  return 0;
}

我将一个字符串(char 数组)声明为仅在while{} 中有效的局部变量。但是我将它的数组地址保存到了指针p,它在while{} 之外也有效。可以通过pwhile{}之外使用字符串吗?

如果没问题,为什么会起作用?

【问题讨论】:

    标签: c variables pointers scope local-variables


    【解决方案1】:

    可以通过pwhile{}之外使用字符串吗?

    。在while 的范围内,p 指向str 的第一个字符。在while 之外没有str,因此没有p 指向的有效内存位置。

    str声明中使用static存储类说明符可以达到想要的效果

    static char str[] = "string";  
    

    while之外你可以使用p

    printf("%s\n", p);  
    

    这是因为在块中声明的static 变量在整个程序执行过程中驻留在相同的存储位置。

    【讨论】:

    • 一个更干净的解决方案是移动行 char str[] = "string";到 while 循环之上,因此它在循环期间及之后的范围内。 static 会导致变量永久消耗 RAM 而不是在堆栈上。
    • @AshleyDuncan a更简洁的解决方案是为字符串动态分配内存。
    【解决方案2】:

    不,这不行。这就是所谓的悬空指针。如果您在程序尝试重用此地址之前设法使用内存,您仍然可能得到预期的结果。但是,如果再次使用内存,您会得到意想不到的结果和很难定位的错误。

    【讨论】:

    • 是的,但实际上比这更糟。正如预期的那样,代码在某些 C 实现中可能可靠地工作,但 C 并不要求它这样做。在支持这种行为的实现上开发依赖于这种行为的代码会给任何试图移植它的人设置陷阱(甚至可能移植到同一平台上的不同 C 实现)。
    • @John Bollinger:非常真实,这是一个等待咬人的陷阱!只是更改编译器标志,优化设置可能会触发它,更不用说更新版本的编译器......绝对必须避免未定义的行为。
    【解决方案3】:

    以这个为例,它可能不适用于所有编译器,但在 OS X 上的 Xcode 中,我得到了这个结果:

    pa:苹果
    pa:橙色
    po:橙色

    #include <stdio.h>
    char *pa;
    char *po;
    
    void apples(void)
    {
        char sa[]="apples";
        pa = sa;
        printf("pa: %s\n", pa);
    }
    
    void orange(void)
    {
        char so[]="orange";
        po = so;
        printf("pa: %s\n", pa);
        printf("po: %s\n", po);
    }
    
    int main(void)
    {
        apples();
        orange();
        return 0;
    }
    

    对 apples() 和 orange() 的每个函数调用随后都会增长然后缩小堆栈,您可以看到字符串(applesorange)如何结束在堆栈上的相同内存位置。但是,一旦超出范围,字符串就会出现为零的保证。这个技巧在这里“有效”,但非常危险。

    作为一个额外的练习,在调用 orange() 之后尝试在 main() 中打印 po 的内容,在大多数情况下,字符串将消失,因为对 printf() 的调用会覆盖堆栈上的空间。

    【讨论】:

      【解决方案4】:

      str 指向进程的只读(数据)区域。您也可以使用 p 访问(读取)该数据。但是,尝试写入该位置会导致分段错误。

      【讨论】:

      • 但是,在while 范围内,"string" 是在char [] 中定义的,而不是在char * 中定义的。如您所述,我了解到字符指针将字符串文字保存在只读内存中,但在字符数组的情况下,可以修改字符串文字。见我在char str[] 中声明了“字符串”,这是第二种情况,字符数组。这让我很困惑。 (参考:stackoverflow.com/questions/1704407/…,Rickard 的回答。
      • 没有。 str 是一个局部变量,分配在堆栈上。 "string"initializer,而不是字符串文字;它与str 的元素所在的位置无关。
      • 你是对的。在堆栈上分配了 7 个字节(“字符串”的每个字符 6 个,终止 '\0' 的每个字符 1 个)内存,“字符串”被复制到那里。由于该内存在堆栈上,因此使用 p 您可以在那里读写(请注意不要写太多以免导致堆栈溢出 - 除非那是您想要的:))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-12
      • 2015-10-08
      • 2020-03-01
      相关资源
      最近更新 更多