【问题标题】:initializing char pointers初始化字符指针
【发布时间】:2010-12-12 05:44:12
【问题描述】:

我有一个用于存储字符串的 char 指针。稍后在程序中使用它。

我已经这样声明和初始化了:

char * p = NULL;

我只是想知道这是否是一种好习惯。我正在使用 gcc 4.3.3。

【问题讨论】:

  • 我猜,他是在问他是否应该将该“字符串”初始化为 NULL(或 0)、“”或根本不初始化它。
  • 这里需要注意,NULL通常 0,但根据标准可能会有所不同:The macro NULL, defined in any of <clocale>, <cstddef>, <cstdio>, <cstdlib>, <cstring>, <ctime>, or <cwchar>, is an implementation-defined C++ null pointer constant in this International Standard。我肯定会坚持使用 NULL,除了它比 0 更“面向类型”并且在源代码中更具描述性。
  • int 值0,当转换为指针类型时,总是产生一个空指针。从可移植性的角度来看,您所做的没有任何区别,NULL 是否只是 0 都没有关系。这仍然留下了“更具描述性”的论点,对此意见不一。反诉相当于 NULL 宏是一个稍微泄漏的抽象和误用时误导(int i = NULL;
  • @RedGlyph:不同的语言;您引用的是 C++ 而不是 C。C 甚至没有 <clocale> 等标头。
  • 首选样式:在 C 中:char * c = NULL;在 C++ 中:char * c = 0;

标签: c pointers char-pointer


【解决方案1】:

是的,这是个好主意。 Google Code Style推荐:

  1. 初始化所有变量,即使您现在不需要它们。
  2. 将指针初始化为NULLint 的 0 和 float 的 0.0 -- 只是为了更好的可读性。

    int i = 0;
    double x = 0.0;
    char* c = NULL;
    

【讨论】:

  • 顺便说一句,那是 C++ 风格指南。它没有告诉我们 Google 对 C 的评价(如果有的话)。
  • @onebyone:即便如此,将指针初始化为 NULL 并在释放它们后将它们设置为 NULL 是一种很好的做法。它使在取消引用它们之前测试它们变得更容易,尤其是在复杂代码中。这在 C 或 C++ 中是正确的。
  • @onebyone 你是对的,我是 c++ 开发人员,在问题中看到了 c++ 语法 =) 但是 O 认为关于 NULL 的规则对 C 来说也是一个很好的做法。
  • 第一部分 - “首选始终初始化” - 仅在 C 99 和 C++ 中可接受,其中可以在代码中的任何位置进行声明。在经典的 C89/90 中,这是一个主要的反规则。不要把你的代码浪费在这样的废话上。第二部分 - “使用特定类型的初始化程序” - 在任何情况下都是反规则。它违反了良好编程的最重要规则之一:不要在没有充分理由的情况下引入任何冗余。浮点值可以由0(与0.0 相对)安全且成功地初始化。
  • 使用0.0 不会提高可读性,并且会在初始化的左侧和右侧之间引入冗余的类型依赖性。将NULL 用于指针可能是允许的,但在所有其他情况下,最好使用简单的0 来初始化可以用它初始化的所有内容。显然,谷歌代码风格比我想象的更随意。
【解决方案2】:

最好初始化所有变量。

【讨论】:

    【解决方案3】:

    您不能将字符串存储在指针中。

    您对mgt_dev_name 的定义很好,但您需要将它指向某个位置,并为您的字符串留出空间。 malloc() 该空格或使用先前定义的字符数组。

    char *mgt_dev_name = NULL;
    char data[4200];
    
    /* ... */
    
    mgt_dev_name = data; /* use array */
    
    /* ... */
    
    mgt_dev_name = malloc(4200);
    if (mgt_dev_name != NULL) {
        /* use malloc'd space */
        free(mgt_dev_name);
    } else {
        /* error: not enough memory */
    }
    

    【讨论】:

    • 我不知道这是不是他要问的,但这是我想知道的。具体来说,如何初始化为 NULL 并稍后为字符串分配空间。
    【解决方案4】:

    如果您问是否有必要,或者在稍后将其设置为其他值之前将变量初始化为 NULL 是否是个好主意:不必将其初始化为 NULL,它不会'不会对程序的功能产生任何影响。

    请注意,在编程中,理解每一行代码非常重要——为什么会出现它以及它到底在做什么。不要在不知道它们的含义或不理解为什么要这样做的情况下做事。

    【讨论】:

    • 其实他应该初始化为NULL。从技术上讲,即使指向不属于您的程序的内存也会使其格式错误,因此通过将其设置为 NULL,您可以避免这种情况。 (这是一种很好的编码习惯)
    • 但在我看来,不初始化变量更容易出错。
    • @GMan - 但是如果他在几行之后将变量初始化为其他值,而中间没有对变量做任何事情,那就没有必要了。
    • 对于运行时行为是不必要的,但是为了制作一个格式良好的程序,它应该被初始化。
    • “即使指向不属于您的程序的内存也会使其格式错误”。不,它没有。以下代码是具有已定义行为的有效 C:char *c; c = "hello, world";。以下是:char *c = malloc(13); free(c); /* c points to memory I don't own! */ c = NULL;
    【解决方案5】:

    另一种选择是在代码中您可以访问它的初始值的位置之前不定义变量。所以与其做:

    char *name = NULL;
    
    ...
    
    name = initial_value;
    

    我会把它改成:

    ...
    
    char *name = initial_value;
    

    然后编译器将阻止您在代码中没有值的部分引用该变量。根据代码的具体情况,这可能并不总是可行(例如,初始值设置在内部范围内,但变量具有不同的生命周期),尽可能晚地在代码中移动定义可以防止错误。

    也就是说,这仅允许从 c99 标准开始(它也是有效的 C++)。要在 gcc 中启用 c99 功能,您需要执行以下任一操作:

    gcc -std=gnu99
    

    或者如果您不希望 gcc 对标准进行扩展:

    gcc -std=c99
    

    【讨论】:

      【解决方案6】:

      不,如果我正确理解您的上下文,这不是一个好习惯。

      如果您的代码实际上依赖于具有空指针初始值的mgt_dev_name,那么当然,将初始化程序包含在声明中是一个非常好的主意。 IE。如果你不得不这样做

      char *mgt_dev_name;
      
      /* ... and soon after */
      mgt_dev_name = NULL;
      

      那么使用初始化而不是赋值总是一个更好的主意

      char *mgt_dev_name = NULL;
      

      然而,只有当你可以用一个有意义的 有用的 值来初始化你的对象时,初始化才是好的。您实际需要的值。在一般情况下,这仅在允许在代码中的任何位置声明的语言中是可能的,C99 和 C++ 是此类语言的良好示例。当您需要您的对象时,您通常已经知道该对象的适当初始化程序,因此可以轻松提出具有良好初始化程序的优雅声明。

      另一方面,在 C89/90 中,声明只能放在块的开头。那时,在一般情况下,您不会对所有对象都有有意义的初始化程序。你是否应该用一些东西来初始化它们,任何东西(如0NULL)只是为了让它们初始化?不!!!永远不要在你的代码中做无意义的事情。不管各种“风格指南”会告诉你什么,它都不会改善任何东西。实际上,无意义的初始化实际上可能会掩盖代码中的错误,从而使发现和修复它们变得更加困难。

      请注意,即使在 C89/90 中,争取更好的声明位置总是有益的。 IE。一个著名的良好实践指南指出:始终使您的变量尽可能本地化。不要在函数一开始就堆积所有本地对象声明,而是将它们移到尽可能紧密地包围对象整个生命周期的最小块的开头。有时,为了提高声明的局部性,引入一个虚构的、否则不必要的块甚至可能是个好主意。遵循这种做法将帮助您在许多(如果不是大多数)情况下为您的对象提供有用的初始化器。但是某些对象在 C89/90 中将保持未初始化状态,只是因为在声明时您没有一个好的初始化器。不要仅仅为了初始化它们而尝试用“某物”来初始化它们。这绝对不会带来任何好处,而且实际上可能会产生负面影响。

      请注意,一些现代开发工具(例如 MS Visual Studio 2005)会在代码的调试版本中捕获对未初始化变量的运行时访问。即这些工具可以帮助您在变量有机会获得有意义的值之前检测到访问变量的情况,这表明代码中存在错误。但是,对变量执行无条件的过早初始化实际上会扼杀工具的这种功能并将这些错误扫到地毯下。

      【讨论】:

        【解决方案7】:

        这里已经讨论过这个话题:

        http://www.velocityreviews.com/forums/t282290-how-to-initialize-a-char.html

        它指的是 C++,但它也可能对你有用。

        【讨论】:

          【解决方案8】:

          这个问题有几个很好的答案,其中一个已被接受。无论如何,我都会回答以扩展实用性。

          是的,最好将指针初始化为 NULL,并在不再需要(即释放)指针后将指针设置为 NULL。

          在任何一种情况下,能够在取消引用之前测试指针是非常实用的。假设您有一个如下所示的结构:

          struct foo {
              int counter;
              unsigned char ch;
              char *context;
          };
          

          然后您编写一个应用程序,该应用程序生成多个线程,所有线程都通过使用互斥在一个分配的 foo 结构上(安全地)运行。

          线程 A 在 foo 上获得锁,增加计数器并检查 ch 中的值。它没有找到一个,所以它不分配(或修改)上下文。相反,它在 ch 中存储一个值,以便线程 B 可以代替执行此工作。

          线程 B 看到计数器已经增加,注意到 ch 中的一个值,但不确定线程​​ A 是否对上下文做了任何事情。如果 context 被初始化为 NULL,线程 B 不再需要关心线程 A 做了什么,它知道 context 可以安全地取消引用(如果不是 NULL)或分配(如果 NULL)而不会泄漏。

          线程 B 执行其业务,线程 A 读取其上下文,释放它,然后将其重新初始化为 NULL。

          同样的推理也适用于全局变量,但不使用线程。能够在取消引用它们(或尝试分配它们从而导致程序中的泄漏和未定义行为)之前在各种函数中测试它们是很好的。

          当指针的范围没有超出单个函数时,它变得愚蠢。如果您有一个函数并且无法跟踪其中的指针,通常这意味着应该重构该函数。但是,如果只是为了保持统一的习惯,在单个函数中初始化指针并没有错。

          我见过的唯一一次依赖初始化指针的“丑陋”案例(使用前后)是这样的:

          void my_free(void **p)
          {
              if (*p != NULL) {
                  free(*p);
                  *p = NULL;
              }
          }
          

          不仅在严格的平台上取消引用类型双关指针不受欢迎,上面的代码使 free() 更加危险,因为调用者会有一些安全错觉。除非您确定每个操作都一致,否则您不能依赖实践“批发”。

          可能比您实际想要的信息多得多。

          【讨论】:

            【解决方案9】:

            首选样式:

            在 C 中:char * c = NULL;

            在 C++ 中:char * c = 0;

            【讨论】:

              【解决方案10】:

              我的理由是,如果您不使用 NULL 进行初始化,然后完全忘记初始化,那么在取消引用时您将在代码中遇到的错误种类将更难以追踪,因为其中可能存在垃圾那个时候的记忆。另一方面,如果你初始化为NULL,大多数时候你只会得到一个segmentation fault,考虑到替代方案,这会更好。

              【讨论】:

                【解决方案11】:

                即使您不需要立即初始化变量,初始化变量也是一种很好的做法。通常,我们将指针初始化为 NULL,将 int 初始化为 0,并将浮点数初始化为 0.0。

                int* ptr = NULL;
                int i = 0;
                float r = 0.0;
                

                【讨论】:

                  【解决方案12】:

                  在 C++ 中初始化指针变量总是好的,如下所示:

                  int *iPtr = nullptr;
                  char *cPtr = nullptr;
                  

                  因为如上所述的初始化将有助于以下条件,因为 nullptr 可以转换为 bool,否则您的代码最终会抛出一些编译警告或未定义的行为:

                  if(iPtr){
                     //then do something.
                  }
                  
                  if(cPtr){
                    //then do something.
                  }
                  

                  【讨论】:

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