【问题标题】:string manipulations in CC中的字符串操作
【发布时间】:2012-09-26 10:33:45
【问题描述】:

以下是我对 C 中的字符串的一些基本问题。

  • 如果字符串字面量存储在只读数据段中,初始化后无法更改,那么以下两种初始化有什么区别。

char *string = "你好世界";

const char *string = "Hello world";

  • 当我们为字符串动态分配内存时,我看到以下分配足以容纳任意长度的字符串。虽然这种分配工作,但我理解/相信分配实际字符串的实际大小总是一个好习惯而不是数据类型的大小。请指导正确使用字符串的动态分配。

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

scanf("%s",str);

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

【问题讨论】:

  • 一次只能回答一个问题

标签: c string malloc literals


【解决方案1】:

1.以下两种初始化有什么区别。 不同之处在于错误的编译和运行时检查,正如其他人已经告诉过的那样。

char *string = "Hello world";--->存储在只读数据段和 无法更改,但如果更改值,则编译器不会给出 它只会在运行时出现任何错误。

const char *string = "Hello world";--->这也是存储在读 只有具有编译时检查的数据段,因为它被声明为 const 所以如果你改变字符串的值,那么你会得到一个 编译时出错,比运行时出错要好得多。

2.请指导正确使用字符串动态分配。

 char *str = (char *)malloc(sizeof(char));
 scanf("%s",str);
 printf("%s\n",str);

这段代码可能会工作一段时间,但并非总是如此。问题出现在run-time 时,您将获得segmentation fault,因为您正在访问不属于您的程序的area of memory。您应该始终非常小心在这个dynamic memory allocation,因为它会导致非常危险的error at run time。

您应该始终allocate the amount of memory you need correctly。 最大的错误出现在use of string 期间。您应该始终牢记is a '\0' character present at last of the string 和分配期间your responsibility to allocate memory for this.

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    以下两个初始化有什么区别。

    由于遗留原因,字符串文字的类型为 char*。最好只通过const char* 指向它们,因为不允许修改它们。

    我看到以下分配足以容纳任意长度的字符串。

    错了。此分配只为一个字符分配内存。如果您尝试向string 写入多个字节,则会出现缓冲区溢出。

    动态分配内存的正确方法很简单:

    char *string = malloc(your_desired_max_length);
    

    这里显式转换是多余的,sizeof(char) 定义为 1。

    另外:记住字符串终止符 (0) 也必须适合字符串。

    【讨论】:

    • your_desired_max_length + 1(最后需要为 null 留出空间),而且演员表不仅是多余的,而且是危险的。
    • “我看到以下分配足以容纳任意长度的字符串”:我这样说是基于一个事实,即最初为一个字符分配一个字节并使用它的指针。我能够读取一个 > 1 个字节的字符串。但它不会像你说的那样在所有情况下都有效,导致溢出。
    【解决方案3】:

    在第一种情况下,您将char* 显式转换为const,这意味着您不允许在编译器级别对其后面的字符进行更改。在 C 中,尝试修改这些字符实际上是未定义的行为(在运行时),而不管它们的 const 性如何,但字符串文字 是 char *,而不是 const char *。

    在第二种情况下,我发现了两个问题。

    首先,你不应该从malloc 转换返回值,因为它可以掩盖某些错误(尤其是在指针和整数大小不同的系统上)。具体来说,除非存在活动的malloc 原型,否则编译器可能会假定它返回int 而不是正确的void *。

    因此,如果您忘记包含 stdlib.h,您可能会遇到一些编译器无法警告您的有趣行为,因为您通过显式转换告诉它您知道你什么正在做。

    C 完全能够在从 malloc 返回的 void * 和任何其他指针类型之间进行隐式转换。

    第二个问题是它只为一个字符分配空间,这将是一个字符串的终止空值。

    最好写成:

    char *string = malloc (max_str_size + 1);
    

    (永远不要乘以 sizeof(char),那是浪费时间 - 总是 1)。

    【讨论】:

      【解决方案4】:

      这两个声明之间的区别在于,如果尝试通过 const char* 声明的指针修改字符串文字,编译器将产生错误(这比运行时失败要好得多)。以下代码:

      const char* s = "hello"; /* 's' is a pointer to 'const char'. */
      *s = 'a';
      

      结果VC2010发出如下错误:

      错误 C2166:左值指定 const 对象

      直到运行时才会检测到通过char* 声明的指针修改字符串文字的尝试(VC2010 不会发出错误),其行为未定义。

      当malloc()ing 内存用于存储字符串时,您必须记得分配一个额外的char 用于存储空终止符,因为所有(或几乎所有)C 字符串处理函数都需要空终止符.例如,分配一个缓冲区来存储"hello":

      char* p = malloc(6); /* 5 for "hello" and 1 for null terminator. */
      

      sizeof(char) 保证为 1,因此不是必需的,也不需要强制转换 malloc() 的返回值。当不再需要p 时,请记住free() 分配的内存:

      free(p);
      

      【讨论】:

        【解决方案5】:

        以下两种初始化的区别。

        首先,char *string = "Hello world";
        - “Hello world”作为常量字符串存储在堆栈段中,其地址分配给指针'string'变量。
        “你好世界”是不变的。而且你不能做string[5]='g',这样做会导致分段错误。
        其中“字符串”变量本身不是恒定的。您可以更改其绑定:
        string="其他字符串"; //这是正确的,没有分段错误

        const char *string = "Hello world";
        再次将“Hello world”作为常量字符串存储在堆栈段中,并将其地址分配给“字符串”变量。 并且 string[5]='g',这会导致分段错误。
        这里没有使用 const 关键字!

        现在,
        char *string = (char *)malloc(sizeof(char));

        上面的声明与第一个相同,但这次你的赋值是来自堆段(而不是堆栈)的动态

        【讨论】:

        • 我相信字符串文字存储在数据段的只读部分而不是堆栈中
        • 当然,字符串文字以只读方式存储。我说的是分配的内存。
        • 我有疑问,你的第二个是“但绑定也不能改变'字符串',因为这个字符串不是更多的变量标识符,而是它的常量标识符。所以,string = “其他一些字符串"; //会导致编译错误; "这不正确,因为它现在还不是一个常量指针。我编译这个时没有错误。
        • @pradipta 你是对的......但现在我更正了我的答案......谢谢!
        【解决方案6】:

        代码:

        char *string = (char *)malloc(sizeof(char));
        

        不会保存任意长度的字符串。它将分配一个字符并返回一个指向 char 字符的指针。请注意,指向字符的指针和指向所谓字符串的指针是一回事。

        要为字符串分配空间,您必须执行以下操作:

        char *data="Hello, world";
        char *copy=(char*)malloc(strlen(data)+1);
        strcpy(copy,data);
        

        您需要准确地告诉malloc 要分配多少字节。 +1 用于需要结束的空终止符。

        至于将文字字符串存储在只读段中,这是一个实现问题,尽管几乎总是如此。大多数 C 编译器对 const'ing 访问这些字符串非常放松,但尝试修改它们是自找麻烦,因此您应该始终将它们声明为 const char * 以避免任何问题。

        【讨论】:

          【解决方案7】:

          由于程序堆中可能有足够的空间,该特定分配可能看起来有效,但事实并非如此。您可以通过使用建议的方法分配两个“任意”字符串并 memcpy: 将一些足够长的字符串分配给相应的地址来验证它。在最好的情况下你会看到垃圾,在最坏的情况下你会遇到分段错误或来自 malloc 或 free 的断言。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-06-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多