Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
何时将内存分配给char*_C_String_Pointers_Malloc_Constants - Fatal编程技术网

何时将内存分配给char*

何时将内存分配给char*,c,string,pointers,malloc,constants,C,String,Pointers,Malloc,Constants,我有点困惑什么时候把内存分配给char*以及什么时候把它指向const字符串 是的,我知道如果我想修改字符串,我需要为它分配内存 但是,如果我不想修改我指向的字符串,只需要传递值,我应该执行以下操作吗?与使用malloc分配内存相比,以下步骤有哪些缺点 char *str = NULL; str = "This is a test"; str = "Now I am pointing here"; 只要不打算修改该字符串的内容,代码中就没有问题。此外,这些字符串文本的内存将在程序的整个生命

我有点困惑什么时候把内存分配给char*以及什么时候把它指向const字符串

是的,我知道如果我想修改字符串,我需要为它分配内存

但是,如果我不想修改我指向的字符串,只需要传递值,我应该执行以下操作吗?与使用
malloc
分配内存相比,以下步骤有哪些缺点

char *str = NULL;

str = "This is a test";

str = "Now I am pointing here";

只要不打算修改该字符串的内容,代码中就没有问题。此外,这些字符串文本的内存将在程序的整个生命周期内保留。由
malloc
分配的内存是读写,因此您可以操作该内存的内容。

不幸的是,在C语言中这是合法的,但任何通过指针修改字符串文字的尝试都将导致未定义的行为


它将正常运行,但编译器可能会发出警告,因为您指向的是一个常量字符串


注意:只有在您不修改它时,它才会正常运行。因此,不使用
malloc
的唯一缺点是您将无法修改它。

如果您有一个不想修改的字符串文本,那么您所做的是可以的:

char *str = NULL;
str = "This is a test";
str = "Now I am pointing here";
这里
str
指针有一个指向的内存。在第二行中,您写入该内存
“这是一个测试”
,然后在第三行中,您写入该内存
“现在我指向这里”
。这在C语言中是合法的

您可能会发现它有点矛盾,但您不能修改类似这样的字符串-

str[0]='X' // will give a problem.
但是,如果您希望能够修改它,请将其用作缓冲区以保存输入行等,请使用
malloc

char *str=malloc(BUFSIZE);   // BUFSIZE size what you want to allocate
free(str);                   // freeing memory

当您不知道编译时所需的内存量时,请使用
malloc()

让我们使用
-Wwrite strings
编译器警告标志重试您的示例,您将看到一条警告:

warning: initialization discards 'const' qualifier from pointer target type
这是因为“这是一个测试”的类型是
const char*
,而不是
char*
。因此,当您将文本地址分配给指针时,将丢失常量信息

出于历史原因,编译器将允许您存储字符串文字,这些文字是非常量变量中的常量

但是,这是一种不好的行为,我建议您始终使用
-Wwrite strings

如果您想自己证明,请尝试修改字符串:

char *str = "foo";
str[0] = 'a';
此程序行为未定义,但您可能会在许多系统上看到分段错误。 使用运行此示例时,您将看到以下内容:

Process terminating with default action of signal 11 (SIGSEGV)
  Bad permissions for mapped region at address 0x4005E4
问题是编译器生成的二进制文件将字符串文本存储在内存位置。试图在上面写,你会引起一场灾难

重要的是要了解,您在这里处理的是两种不同的系统:

  • C打字系统可以帮助您编写正确的代码,并且可以轻松地“静音”(通过强制转换等方式)

  • 内核内存页权限,用于保护您的系统,并且应始终遵守

  • 同样,出于历史原因,这是一个1。二,。不同意。或者更清楚地说,1。比2更宽容。(导致程序被内核终止)

    因此,不要被编译器愚弄,您声明的字符串文字实际上是常量,您对此无能为力

    考虑到您的指针
    str
    read和write是可以的。 但是,要编写正确的代码,它应该是
    const char*
    ,而不是
    char*
    。通过以下更改,您的示例是一段有效的C:

    const char *str = "some string";
    str = "some other string";
    
    常量字符*
    指向常量字符串的指针)

    在这种情况下,编译器不会发出任何警告。代码执行后,您编写的内容和内存中的内容将匹配

    注意:指向常量字符串的常量指针为
    const char*const

    const char *const str = "foo";
    
    int countLettersInString(char c, char const * str);
    
    经验法则是:尽可能保持恒定


    如果您需要修改字符串,请使用动态分配(malloc()或更好,一些更高级别的字符串操作函数,如libc中的strdup等),如果您不需要,请使用字符串文字。

    如果您知道
    str
    将始终是只读的,为什么不将其声明为只读呢

    char const * str = NULL;
    /* OR */
    const char * str = NULL;
    
    事实上,这可能很困难,有一个原因——当您将字符串传递给一个只读函数时,该函数不声明自己为只读函数。假设您正在使用声明此函数的外部库:

    int countLettersInString(char c, char * str);
    /* returns the number of times `c` occurs in `str`, or -1 if `str` is NULL. */
    
    这个函数有很好的文档记录,您知道它不会试图更改字符串
    str
    ——但是如果您使用常量字符串调用它,编译器可能会给您一个警告!你知道它没有什么危险,但是你的编译器没有

    为什么??因为就编译器而言,可能这个函数确实试图修改字符串的内容,这会导致程序崩溃。也许你非常依赖这个库,有很多函数都是这样的。那么,一开始不将字符串声明为
    const
    可能会更容易些,但接下来就要由您来确定是否尝试修改它了

    另一方面,如果您是编写
    countletersinstring
    函数的人,那么只需确保编译器知道您不会通过使用
    const
    声明字符串来修改它:

    const char *const str = "foo";
    
    int countLettersInString(char c, char const * str);
    

    这样一来,它就可以毫无疑问地接受常量和非常量字符串。

    使用字符串文字的一个缺点是它们有长度限制。 因此,您应该记住文件ISO/IEC:9899 (强调矿山)

    5.2.4.1翻译限制

    1实现应能够翻译和执行至少一个程序,该程序至少包含以下各项的一个实例