【问题标题】:C string scope between functions函数之间的 C 字符串范围
【发布时间】:2016-03-19 13:44:23
【问题描述】:

我的问题很难用语言表达,所以我只给出一个代码示例:

#include <stdio.h>

typedef struct {
    char *str;
} strHold;

void f2(char *s)
{
    *s = "Char 2";
}

void f3(strHold *str)
{
    (*str).str = "Struct 2";
}

int main()
{
    char *s1 = "Char 1";
    strHold str1;
    str1.str = "Struct 1";

    //f2(s1);
    f3(&str1);

    printf("%s, ", s1);
    printf("%s", str1.str);

    return 0;
}

这个 C 程序运行,甚至在第二次打印时显示“Struct 2”。但是函数 f2 不起作用,例如,如果我删除评论,程序就会崩溃。 我其实并不惊讶 f2 不起作用,我更想知道为什么 f3 起作用?

当我在函数范围内定义字符串常量时,一旦我退出函数范围,就应该释放该数据,对吗?这意味着一旦我返回调用函数范围,数据就会变成垃圾。

那么...结构版本是如何工作的?有人可以解释一下内存在这两种情况下是如何工作的,以及在调用函数中从它调用的函数初始化未知长度的字符串的“正确”方法是什么?

【问题讨论】:

  • 在构建、阅读它们、尝试理解它们的含义并修复警告的根本原因时,您应该从这个程序中得到很多警告(并且通过“修复”我不只是扔掉警告)。
  • 还了解如何在 c 中模拟通过引用传递

标签: c


【解决方案1】:

你的编译器应该对这一行给出警告:

*s = "Char 2";

这里,*s 是一个char,您尝试为其分配一个字符串(char*)。通过将s1 的地址传递给函数来修复它:

f2(&s1);

并将函数头更改为:

void f2(char **s)

当我在函数范围内定义字符串常量时,一旦我退出函数范围,就应该释放该数据,对吗?这意味着一旦我返回调用函数范围,数据就会变成垃圾。

没有。字符串文字具有静态生命周期,这意味着它们只要程序存在就存在。一旦函数结束,只有函数内部的局部变量会被销毁。

【讨论】:

  • 这是最有用的答案。我之前注意到我的错误 f2 并在调用中固定为 &s1 并在标头中固定为 **s,但是存储字符串文字的方式是我真正的问题,你回答了这个问题,所以现在我知道我在做什么了。谢谢。
【解决方案2】:

你不能尝试修改字符串文字,否则你会调用未定义的行为

"Char 1" 被赋值,所以f2 的参数s 包含一个指向字符串文字的指针。因此,给*s 赋值意味着你正在尝试修改一个字符串字面量。

要修改调用者的局部变量,请使用指向要修改的变量的指针。

根据N1256 6.4.5 String literals-5 和N1570 6.4,您不必释放字符串文字,也不能尝试释放它们,因为它们分配有静态存储持续时间。 5 字符串字面量-6.

结构版本有效,因为您将指针传递给结构并使用它来修改结构的成员,而无需尝试修改任何字符串文字。

此代码将起作用:

#include <stdio.h>

typedef struct {
    char *str;
} strHold;

void f2(char **s) /* add * to receive a pointer to char* */
{
    *s = "Char 2";
}

void f3(strHold *str)
{
    (*str).str = "Struct 2";
}

int main(void)
{
    char *s1 = "Char 1";
    strHold str1;
    str1.str = "Struct 1";

    f2(&s1); /* add & to get the pointer to s1 */
    f3(&str1);

    printf("%s, ", s1);
    printf("%s", str1.str);

    return 0;
}

【讨论】:

    【解决方案3】:

    在:

    void f2(char *s)
    {
        *s = "Char 2";
    }
    

    你会得到一个编译器错误:你是 dereference 指针,它产生一个字符(类型),现在想要为该字符分配一个 string

    更一般地说,字符串文字必须存储在内存中的某个位置,否则程序无法为其赋值。所以离开函数后,文字仍然存储在内存中的某个地方。

    【讨论】:

      【解决方案4】:

      你使用的指针,*s1应该指向一个足够大的内存块,对于初学者来说,使用一个足够长的字符串来包含你最长的输出。更有经验的程序员应该适当地使用 malloc 和 free。

      对于初学者:

      static char buffer[80]; /* 80 chars of null bytes */
      char        *s1;        /* pointer to string */
      s1 = buffer;          /* pointer now pointing to beginning of buffer */
      strcpy(s1,"Char 1")   /* buffer now contains initial text,
        rest is null bytes, so string is terminated correctly */
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多