【问题标题】:Difference between char *str="STRING" and char str[] = "STRING"?char *str="STRING" 和 char str[] = "STRING" 的区别?
【发布时间】:2011-04-21 05:48:22
【问题描述】:

在编写一个从字符串中删除特定字符的简单函数时,我遇到了一个奇怪的问题:

void str_remove_chars( char *str, char to_remove)
{
    if(str && to_remove)
    {
       char *ptr = str;
       char *cur = str;
       while(*ptr != '\0')
       {
           if(*ptr != to_remove)
           {
               if(ptr != cur)
               {
                   cur[0] = ptr[0];
               }
               cur++;
           }
           ptr++;
       }
       cur[0] = '\0';
    }
}
int main()
{
    setbuf(stdout, NULL);
    {
        char test[] = "string test"; // stack allocation?
        printf("Test: %s\n", test);
        str_remove_chars(test, ' '); // works
        printf("After: %s\n",test);
    }
    {
        char *test = "string test";  // non-writable?
        printf("Test: %s\n", test);
        str_remove_chars(test, ' '); // crash!!
        printf("After: %s\n",test);
    }

    return 0;
}

我不明白为什么第二次测试失败了? 在我看来,第一个符号 char *ptr = "string"; 等同于这个符号:char ptr[] = "string";

不是这样吗?

【问题讨论】:

标签: c arrays string pointers stack


【解决方案1】:
char *str = strdup("test");
str[0] = 'r';

是正确的代码并创建一个可变字符串。 str 在堆中分配了一块内存,其中填充了值'test'。

【讨论】:

  • 下摆。那么,每次执行函数,分配5个字节?
【解决方案2】:

这两个声明不一样。

char ptr[] = "string"; 声明一个大小为 7 的 char 数组并用字符初始化它
s ,t,r,i,n,g 和 @987654329 @。您被允许修改此数组的内容。

char *ptr = "string";ptr 声明为 char 指针,并使用 字符串字面量 "string" 的地址对其进行初始化,只读。修改字符串文字是一种未定义的行为。您所看到的(段错误)是未定义行为的一种表现。

【讨论】:

  • 对于不同的声明,sizeof(ptr) 也会给出不同的结果。第一个将返回数组的长度包括终止空字符。第二个将返回指针的长度,通常为 4 或 8。
  • 第二点,ptr的内容可以改变也是如此。但内容是指向文字的指针,而不是字符。
  • +1,很好的答案。同样重要的是要理解char *ptr = "string"; ptr 可以指向其他东西,因此可以“更改”它所指向的内容,但字符"string" 是文字,不能更改。
  • 性能问题也值得一提。每次变量进入作用域时,声明一个初始化的自动数组变量将填充整个数组内容。当变量进入作用域时,声明一个初始化的自动指针变量将简单地分配指针(一个单词写入)。如果字符串很长或经常输入块(如循环的每次迭代),则差异可能非常显着!
  • @AmigableClarkKant,实际上,sizeof(ptr) 不是数组的长度,除非 ptr 被声明为 char 数组。如果ptr 定义为具有3 个元素的int 数组,则sizeof(ptr) 将返回每个元素的sizeof(int) 之和。
【解决方案3】:

很好的答案@codaddict。

另外,sizeof(ptr) 将针对不同的声明给出不同的结果。

第一个,数组声明,将返回数组的长度包括终止空字符。

第二个,char* ptr = "a long text..."; 将返回指针的长度,通常为 4 或 8。

【讨论】:

    【解决方案4】:

    char *test = "string test"; 错了,应该是const char*。这段代码编译只是因为向后兼容的原因。 const char* 指向的内存是只读内存,每当您尝试写入它时,它都会调用未定义的行为。另一方面char test[] = "string test" 在堆栈上创建一个可写 字符数组。这就像您可以写入的任何其他常规局部变量一样。

    【讨论】:

    • 我不会说这是错误的。您可能希望稍后让test 指向一个可修改的字符串,并保留一个标志(在另一个变量中),指示它是否已被可修改的东西替换。尽管如此,在大多数情况下,在那里使用const 可能是一种好习惯。
    【解决方案5】:

    我记得

    char ptr[] = "string";
    

    在堆栈上创建"string"副本,所以这个是可变的。

    表格

    char *ptr = "string";
    

    只是向后兼容

    const char *ptr = "string";
    

    并且不允许您(就未定义的行为而言)修改其内容。 编译器可能会将此类字符串放在内存的只读部分中。

    【讨论】:

      【解决方案6】:

      严格来说,char *ptr 的声明只保证你有一个指向字符类型的指针。字符串构成已编译应用程序代码段的一部分并不罕见,某些操作系统会将其设置为只读。问题在于您正在对预定义字符串的性质(它是可写的)做出假设,而实际上您从未为该字符串显式创建内存。编译器和操作系统的某些实现可能会允许您执行您尝试执行的操作。

      另一方面,根据定义,char test[] 的声明实际上在这种情况下为堆栈上的整个字符数组分配了可读和可写的内存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-14
        • 2012-03-16
        • 2020-01-28
        • 1970-01-01
        • 2021-04-10
        • 2018-06-27
        相关资源
        最近更新 更多