【问题标题】:difference between string pointer and string array字符串指针和字符串数组的区别
【发布时间】:2014-12-27 17:41:58
【问题描述】:

我正在编写代码来巩固我的知识,但我遇到了分段错误。所以,我也知道我必须补充(完成不完美的知识)我的知识。问题是关于strtok()。当我运行第一个代码时没有问题,但在第二个中,我得到了分段错误。我的“不完善的知识”是什么?感谢您的赞赏回答。

第一个代码

#include <stdio.h>
#include <string.h>

int main() {



    char str[] = "team_name=fenerbahce";
    char *token;

    token = strtok(str,"=");
    while(token != NULL)
    {
        printf("%s\n",token);
        token = strtok(NULL,"=");
    }
  return 0;
}

第二个代码

#include <stdio.h>
#include <string.h>

int main() {



    char *str= "team_name=fenerbahce";
    char *token;

    token = strtok(str,"=");
    while(token != NULL)
    {
        printf("%s\n",token);
        token = strtok(NULL,"=");
    }
  return 0;
}

【问题讨论】:

    标签: c arrays string pointers segmentation-fault


    【解决方案1】:

    来自strtok -

    这个函数是破坏性的:它在字符串 str 的元素中写入 '\0' 字符。特别是,字符串文字不能用作 strtok 的第一个参数。

    在第二种情况下,str 是驻留在只读内存中的字符串文字。任何修改字符串文字的尝试都会导致未定义的行为。

    【讨论】:

    • 是的,这只是由于(不推荐)转换为char* 而编译。您应该始终使用 char const* 代替,因为这样可以防止您在该字符串上调用 strtok()
    • str = "some string"; 不会创建 char const *,而是创建 const char *
    • @UlrichEckhardt:这种转换在 C 中没有被弃用。
    • @Elias Van Ootegem 好像这两者之间有什么区别。
    • const char*char const* 都是一样的,都是指向 const char @Mahesh 的指针。指向 char 的常量指针是 char* const。一般规则是 const 适用于它左边的东西,除非它是最左边的,否则它适用于右边。因为我不喜欢后一个异常,所以我更喜欢 char const* 作为指向 const 的指针。
    【解决方案2】:

    您会看到字符串文字是您在“”中编写的字符串。对于每个这样的字符串,无论在哪里使用,都会自动分配一个全局空间来存储它。当你将它分配给一个数组时——你将它的内容复制到一个新的内存中,即数组的内存中。否则,您只需存储一个指向它的全局内存存储的指针。

    所以这个:

    int main()
    {
        const char *str= "team_name=fenerbahce";
    }
    

    等于:

    const char __unnamed_string[] { 't', 'e', /*...*/, '\0' };
    
    int main()
    {
       const char *str= __unnamed_string;
    }
    

    而当把字符串赋值给数组时,像这样:

    int main()
    {
        char str[] = "team_name=fenerbahce";
    }
    

    到这里:

    const char __unnamed_string[] { 't', 'e', /*...*/, '\0' };
        
    int main()
    {
           char str[sizeof(__unnamed_string) / sizeof(char)];
           
           for(size_t i(0); i < sizeof(__unnamed_string) / sizeof(char); ++i)
              str[i] = __unnamed_string[i];
    }
    

    如您所见,这是有区别的。在第一种情况下,您只存储一个指针,而在第二种情况下,您将整个字符串复制到本地。

    注意:字符串文字是不可编辑的,因此您应该将它们的地址存储在一个常量中。

    在 N4296 - § 2.13.5 .8 中规定:

    普通字符串文字和 UTF-8 字符串文字也被引用 作为窄字符串文字。窄字符串文字的类型为“数组 n const char”,其中 n 是字符串的大小,定义如下, 并且具有静态存储持续时间

    这个决定背后的原因可能是因为这样,这样的数组可以存储在只读段中,从而以某种方式优化程序。有关此决定的更多信息see

    注1

    在 N4296 - § 2.13.5 .16 中规定:

    评估一个字符串文字会产生一个字符串文字对象 静态存储持续时间,从给定字符初始化为 如上所述。

    这正是我所说的 - 对于每个字符串文字,都会使用它们的内容创建一个未命名的全局对象。

    【讨论】:

      【解决方案3】:
      char *str= "team_name=fenerbahce";
      char str[]= "team_name=fenerbahce";
      

      “不完美”的知识是关于数组和指针的区别!这是关于使用指针创建字符串时无法修改的内存。 创建字符串时,您会分配一些内存来存储这些值(字符串的字符)。在接下来的几行中,当我谈到“在开始时分配的内存”时,我会提到这一点。

      当您使用数组创建字符串时,您将创建一个数组,该数组将包含与字符串中的字符相同的字符。所以你会分配更多的内存。

      当您使用指针创建字符串时,您将指向包含该字符串的内存地址(在开始时分配的那个)。

      您必须假设在开始时创建的内存是不可写的(这就是为什么您会有未定义的行为,这意味着大多数时候会出现分段错误,所以不要这样做)。 相反,当您创建数组时,该内存将是可写的!这就是为什么您只能在这种情况下使用 strtok 之类的命令进行修改

      【讨论】:

        猜你喜欢
        • 2015-08-19
        • 1970-01-01
        • 2013-12-16
        • 1970-01-01
        • 2012-02-04
        • 2010-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多