【问题标题】:Regarding initializing a string as an array关于将字符串初始化为数组
【发布时间】:2014-06-29 15:55:52
【问题描述】:

有人告诉我在初始化这样的字符串时

char str[] = "Hello world!";

编译器将在常量内存中分配一个区域(程序只读),然后将字符串复制到驻留在堆栈中的数组中。我的问题是,我可以在修改给定的副本后读取或指向原始字符串吗?如何?如果不是,为什么字符串首先存在于堆栈之外?

【问题讨论】:

  • 那么,这些数据如何才能进入堆栈中的正确位置?
  • 为什么要这样做?如果您告诉我们您的真正需求,我们可能会提供帮助。
  • 如果str 不在块范围内,则它不是“在堆栈中”。如果它在块范围内并且您从未实际修改其内容,则编译器可以对其进行优化(并直接引用字符串文字进行读取)。
  • 关于具体问题:我可以在修改给定的副本后读取或指向原始字符串吗?如何? 见下文 i>.

标签: c c-strings


【解决方案1】:

这样做是为了提高空间效率。当你写:

char str[] = "Hello world!";

它被有效地编译,就像你写的一样:

static char str_init[] = "Hello world!";
char str[13];
strncpy(str, str_init, 13);

实现这一点的另一种方法可能相当于:

char str[13];
str[0] = 'H';
str[1] = 'e';
 ...
str[11] = '!';
str[12] = 0;

但是对于长字符串,这是非常低效的。对于字符串的每个字符,它不会使用 1 个字节的静态数据,而是对每个字符使用一个完整的指令字(可能是 4 个字节,但在某些体系结构上可能更多)。这将不必要地使初始化数据的大小增加四倍。

【讨论】:

    【解决方案2】:

    因为程序必须在某个地方记住字符串,即你所谓的“恒定记忆”。否则如何知道分配变量时要分配什么值?考虑一个具有给定初始值的变量。在声明之前不会分配变量。但初始值必须存储在其他地方。

    【讨论】:

    • 嗯,它可以编译它,就好像它是char str[13];str[0] = 'H';str[1] = 'e'; ...; str[12] = 0;
    【解决方案3】:

    当这个语句被编译时

    char str[] = "Hello world!";
    

    编译器不会在程序中保留字符串文字。它仅用于初始化数组。

    如果你想保留字符串字面量那么你必须这样写

    char *s = "Hello world!";
    char str[13];
    
    strcpy( str, s );
    

    【讨论】:

    • @Oli Charlesworth 在 C 字符串文字中具有 char [] 类型。
    • 但是尝试修改这样的数组是UB;为防止这种情况,请始终使用const 指针。
    • @Oli Charlesworth 不要尝试修改字符串文字。:)
    • @Oli Charlesworth 我同意使用限定符 const 更好,但在我在帖子中展示的示例中,我想强调 C 字符串文字的类型为 char[]。
    【解决方案4】:

    程序运行时,“Hello world”会以字符串字面量的形式存入内存的常量部分,之后程序会在栈中预留足够的空间,从常量部分逐个字符地复制记忆。不幸的是,您无法访问存储字符串文字的常量部分,因为您告诉程序您希望值是可修改的(存储在堆栈中的字符串),因此它给出了您所要求的内容。

    【讨论】:

      【解决方案5】:

      您的大部分问题已在其他答案中得到解决,但是,我没有看到有人专门解决这个问题:

      关于您的问题: ...我可以在修改给定的副本后读取或指向原始字符串吗?如何? em>

      以下序列演示了如何在修改副本后阅读原件

      char str[] = "hello world"; //creates original (stack memory)
      
      char *str2 = 0;//create a pointer  (pointer created, no memory allocated)
      
      str2 = StrDup(str); populate pointer with original (memory allocated on heap)
      
      str2[5]=0;  //edit copy:  results in "hello" (i.e. modified)  (modifying a location on the heap)
      
      str; //still contains "hello world"  (viewing value on the stack)
      

      编辑(回答评论问题)

      上述答案 解决了在修改副本后访问原始字符串的具体问题。我只是展示了一组可能的步骤来解决这个问题。您也可以编辑原始字符串:

      char str[] = "你好世界!"; //在堆栈内存中创建名为“str”的位置,
      //并为文字字符串分配足够的空间: //“Hello world!”,共13个空格(包括\0)
      strcpy(str, "新字符串"); //用“新字符串”替换原始内容 //旧内容不再可用。

      因此,使用这些步骤,变量 str 中的原始值被更改,不再可用。
      我在原始答案中概述的方法(在顶部)显示了一种方法,您可以制作可编辑的副本,同时保持原始变量。

      在您的评论问题中,您指的是诸如系统内存常量内存之类的东西。通常,系统内存是指系统上的 RAM 实现(即多少物理内存)。 常量内存,我猜你指的是在堆栈上创建的变量所使用的内存。 (继续阅读)

      首先在开发或运行时环境中,存在堆栈内存。这通常默认为某个最大值,例如 250,000 字节。它是大多数开发环境中的预构建可设置值,可供您创建的任何变量使用 在堆栈上。示例:

      int x[10];   //creates a variable on the stack 
                   //using enough memory space for 10 integers.  
      
      int y = 1;   //same here, except uses memory for only 1 integer value  
      

      第二还有所谓的内存。堆内存的数量取决于系统,系统可用的物理内存越多,可用于应用程序中可变内存空间的堆内存就越多。当您动态分配内存时会使用堆内存,例如使用malloc()calloc()realloc()

      int *x=0;        //creates a pointer, no memory allocation yet...
      x = malloc(10);  //allocates enough memory for 10 integers, but the 
                       //memory allocated is from the _heap_  
                       //and must be freed for use by the system
                       //when you are done with it.
      free(x);
      

      我已经在原始帖子(上图)中标记了每个变量使用的内存类型。我希望这会有所帮助。

      【讨论】:

      • 那不只是复制字符串吗?也许问题是我对系统内存的了解不够,无法提出这个问题,但如果我声明“int x = 1;”值 1 是否存储在常量内存中,然后复制到变量 x 中?如果不是,我真的不明白为什么它必须是这样的字符串
      • @Techmaster21 - 在哪里、如何创建变量以及在某些情况下如何提供内存都很重要。有关详细信息,请参阅我的编辑
      猜你喜欢
      • 2011-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-15
      • 2015-07-25
      • 2014-08-23
      • 2011-01-05
      相关资源
      最近更新 更多