在C中初始化字符串的正确方法

时间:2010-11-03 00:18:01

标签: c string char

我见过人们的代码:

char *str = NULL;

我也看到了这一点,

char *str;

我很想知道,初始化字符串的正确方法是什么?什么时候你应该初始化一个字符串w /和w / out NULL?

11 个答案:

答案 0 :(得分:16)

你应该在使用它之前设置它。这是 遵循的唯一规则,以避免未定义的行为。无论是在创建时初始化它还是在使用它之前分配它都是不相关的。

就个人而言,我宁愿永远不要将变量设置为未知值,所以我通常会做第一个变量,除非它设置得非常接近(在几行内)。

事实上,使用C99,您不必再在块的顶部声明本地,我通常会推迟创建它直到它需要,此时它也可以初始化。

请注意,在某些情况下,变量会被赋予默认值(例如,如果它们是静态存储持续时间,例如在文件级别,在任何函数之外声明)。

本地变量没有此保证。所以,如果上面的第二个声明(char *str;)在函数内部,它可能有垃圾并试图使用它将调用前面提到的,可怕的,未定义的行为。

C99标准的相关部分6.7.8/10

  

如果没有显式初始化具有自动存储持续时间的对象,则其值是不确定的。如果没有显式初始化具有静态存储持续时间的对象,则:

     
      
  • 如果它有指针类型,则将其初始化为空指针;
  •   
  • 如果它有算术类型,则初始化为(正数或无符号)零;
  •   
  • 如果是聚合,则根据这些规则初始化(递归)每个成员;
  •   
  • 如果是联合,则根据这些规则初始化(递归)第一个命名成员。
  •   

答案 1 :(得分:5)

我很想知道,初始化字符串的正确方法是什么?

好吧,既然第二个片段定义了一个未初始化的指向字符串的指针,我会说第一个。 :)

一般情况下,如果你想安全地玩它,最好初始化为NULL所有指针;通过这种方式,很容易发现从未初始化的指针派生的问题,因为取消引用NULL指针会产生崩溃(实际上,就标准而言,它是未定义的行为,但在我见过的每台机器上这是一次崩溃。)

但是,您不应该将NULL指针与空字符串混淆:指向string的NULL指针意味着该指针指向任何内容,而空字符串是“真实的”,零长度字符串(即它只包含一个NUL字符)。

char * str=NULL; /* NULL pointer to string - there's no string, just a pointer */
const char * str2 = ""; /* Pointer to a constant empty string */

char str3[] = "random text to reach 15 characters ;)"; /* String allocated (presumably on the stack) that contains some text */
*str3 = 0; /* str3 is emptied by putting a NUL in first position */

答案 2 :(得分:3)

这是关于c变量的一般性问题,而不仅仅是char ptrs。

最佳做法是在声明点初始化变量。即

char *str = NULL;

是一件好事。这种方式你永远不会有未知值的变量。例如,如果稍后在代码中执行

if(str != NULL)
 doBar(str);

会发生什么。 str处于未知(几乎肯定不是NULL)状态

请注意,静态变量将初始化为零/ NULL。如果你问的是当地人或静电,问题就不清楚了

答案 3 :(得分:2)

全局变量由编译器使用默认值初始化,但必须初始化局部变量。

答案 4 :(得分:1)

单位指针应该被认为是未定义的,所以为了避免使用未定义的值产生错误,最好使用

char *str = NULL;

也因为

char *str;

这将只是一个未分配的指针指向某个地方,如果你忘记分配它会导致问题,你将需要分配它(或复制另一个指针)。

这意味着您可以选择:

  • 如果您知道在声明后很快就会分配它,则可以避免将其设置为 NULL(这是一种规则)
  • 在任何其他情况下,如果你想确定,就这样做。如果您尝试在未初始化的情况下使用它,则会出现唯一的实际问题。

答案 5 :(得分:1)

这完全取决于你将如何使用它。在下文中,初始化变量 not 更有意义:

int count;
while ((count = function()) > 0)
{
}

答案 6 :(得分:1)

请勿在声明“以防万一”时将所有指针变量初始化为NULL。

如果你尝试使用一个尚未初始化的指针变量,编译器会发出警告,除非你通过地址将它传递给一个函数(你通常会这样做以便给它一个值)。

初始化指向NULL的指针与将其初始化为敏感值并不相同,并将其初始化为NULL只会禁用编译器告诉您没有将其初始化为合理的价值。

如果你没有得到编译器警告,只在声明时初始化指向NULL的指针,或者你是按地址将它们传递给期望它们为NULL的函数。

如果你不能同时看到指针变量的声明和它在同一个屏幕上被赋予一个值的点,那么你的函数就太大了。

答案 7 :(得分:1)

static const char str[] = "str";

static char str[] = "str";

答案 8 :(得分:1)

因为如果你传递一个NULL值,free()不会做任何事情你可以像这样简化你的程序:

char *str = NULL;

if ( somethingorother() )
{
    str = malloc ( 100 );

    if ( NULL == str )
        goto error;
}

...

error:

cleanup();
free ( str );

如果由于某种原因,thingorother()返回0,如果你没有初始化str,你将会 在任何可能导致失败的地方释放一些随机地址。

我为goto的使用道歉,我知道有些人觉得它很冒犯。 :)

答案 9 :(得分:0)

您的第一个代码段是带初始化的变量定义;第二个片段是一个没有初始化的变量定义。

初始化字符串的正确方法是在定义字符串时提供初始化程序。将它初始化为NULL或其他东西取决于你想用它做什么。

还要注意你所谓的“字符串”。 C没有这样的类型:C上下文中的“字符串”通常表示“[some number of char]数组”。您可以在上面的代码段中找到指向char的指针。

假设您有一个程序需要argv [1]中的用户名并将其复制到字符串“name”。定义name变量时,可以将其保持为未初始化,或将其初始化为NULL(如果它是指向char的指针),或使用默认名称初始化。

int main(int argc, char **argv) {
    char name_uninit[100];
    char *name_ptr = NULL;
    char name_default[100] = "anonymous";

    if (argc > 1) {
        strcpy(name_uninit, argv[1]); /* beware buffer overflow */
        name_ptr = argv[1];
        strcpy(name_default, argv[1]); /* beware buffer overflow */
    }

    /* ... */

    /* name_uninit may be unusable (and untestable) if there were no command line parameters */
    /* name_ptr may be NULL, but you can test for NULL */
    /* name_default is a definite name */
}

答案 10 :(得分:0)

适当的你意味着没有bug?好吧,这取决于具体情况。但是我可以推荐一些经验法则。

首先,请注意C中的字符串与其他语言中的字符串不同。

它们是指向一个字符块的指针。其末尾以0字节或NULL终止符结束。因此null终止字符串。

例如,如果您打算做这样的事情:

char* str;  
gets(str);

或以任何方式与str交互,那么这是一个巨大的bug。原因是因为正如我刚才所说,在C字符串中不是像其他语言一样的字符串。它们只是一个指针。 char * str是指针的大小,始终是。

因此,您需要做的是分配一些内存来保存字符串。

/* this allocates 100 characters for a string 
   (including the null), remember to free it with free() */
char* str = (char*)malloc(100);
str[0] = 0;

/* so does this, automatically freed when it goes out of scope */
char str[100] = "";

然而,有时你需要的只是一个指针 e.g。

/* This declares the string (not intialized) */
char* str;

/* use the string from earlier and assign the allocated/copied
   buffer to our variable */
str = strdup(other_string);

通常,它实际上取决于您期望使用字符串指针的方式。 我的建议是使用固定大小的数组形式,如果你只是在该函数的范围内使用它并且字符串相对较小。或者将其初始化为NULL。然后,您可以显式测试NULL字符串,该字符串在传递给函数时很有用。

请注意,如果您使用的函数只是检查字符串结尾的位置,那么使用数组形式也会出现问题。例如strcpy或strcat函数不关心缓冲区有多大。因此,请考虑使用像BSD的strlcpy& amp; strlcat提供。或strcpy_s& strcat_s(windows)。

许多功能都希望您传入正确的地址。再次,请注意

char* str = NULL;
strcmp(str, "Hello World");

会崩溃很长时间,因为strcmp不喜欢传入NULL。

您已将此标记为C,但如果有人使用C ++并阅读此问题,请切换到尽可能使用std :: string并在需要与API交互的字符串上使用.c_str()成员函数这需要一个标准的空终止c字符串。