我有一个用于存储字符串的 char 指针。稍后在程序中使用它。
我已经这样声明和初始化:
char * p = NULL;
我只是想知道这是否是一种好习惯。我正在使用 gcc 4.3.3。
我有一个用于存储字符串的 char 指针。稍后在程序中使用它。
我已经这样声明和初始化:
char * p = NULL;
我只是想知道这是否是一种好习惯。我正在使用 gcc 4.3.3。
是的,这是个好主意。 谷歌代码风格推荐:
NULL
用, int
's 0 和's 0.0初始化指针float
——只是为了更好的可读性。
int i = 0;
double x = 0.0;
char* c = NULL;
初始化所有变量是一个好习惯。
您不能将字符串存储在指针中。
您的定义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
在稍后将其设置为其他内容之前将变量初始化为一个好主意:不必将其初始化为NULL
,它不会对您的功能产生任何影响程序。
请注意,在编程中,理解每一行代码很重要——它为什么存在以及它到底在做什么。不要在不知道它们的含义或不理解为什么要这样做的情况下做事。
另一种选择是在代码中您可以访问它的初始值的位置之前不定义变量。所以而不是这样做:
char *name = NULL;
...
name = initial_value;
我会将其更改为:
...
char *name = initial_value;
然后,编译器将阻止您在没有值的代码部分引用该变量。根据您的代码的具体情况,这可能并不总是可行(例如,初始值设置在内部范围内,但变量具有不同的生命周期),尽可能晚地在代码中移动定义可以防止错误。
也就是说,这只允许从 c99 标准开始(它也是有效的 C++)。要在 gcc 中启用 c99 功能,您需要执行以下操作:
gcc -std=gnu99
或者如果您不希望 gcc 扩展标准:
gcc -std=c99
不,如果我正确理解您的上下文,这不是一个好习惯。
如果您的代码实际上依赖于mgt_dev_name
具有空指针的初始值,那么当然,将初始化程序包含在声明中是一个非常好的主意。即,如果您无论如何都必须这样做
char *mgt_dev_name;
/* ... and soon after */
mgt_dev_name = NULL;
那么使用初始化而不是赋值总是一个更好的主意
char *mgt_dev_name = NULL;
但是,只有当您可以使用有意义的 有用值初始化对象时,初始化才是好的。您实际需要的值。在一般情况下,这仅在允许在代码中的任何位置声明的语言中是可能的,C99 和 C++ 是此类语言的良好示例。当您需要您的对象时,您通常已经知道该对象的适当初始化程序,因此可以轻松地提出具有良好初始化程序的优雅声明。
另一方面,在 C89/90 中,声明只能放在块的开头。那时,在一般情况下,您不会对所有对象都有有意义的初始化程序。你是否应该用一些东西来初始化它们,任何东西(比如0
或NULL
)只是为了让它们初始化?不!!!永远不要在你的代码中做无意义的事情。不管各种“风格指南”会告诉你什么,它都不会改善任何东西。实际上,无意义的初始化实际上可能会覆盖代码中的错误,从而更难发现和修复它们。
请注意,即使在 C89/90 中,争取更好的声明位置总是有益的。即一个著名的良好实践指南指出:始终使您的变量尽可能本地化。不要在函数的最开始堆积所有的本地对象声明,而是将它们移动到尽可能紧密地包围对象整个生命周期的最小块的开头。有时,为了提高声明的局部性,引入一个虚构的、否则不必要的块甚至可能是个好主意。遵循这种做法将帮助您在许多(如果不是大多数)情况下为您的对象提供有用的初始化器。但是某些对象在 C89/90 中将保持未初始化状态,只是因为在声明时您没有一个好的初始化器。大学教师' 不要仅仅为了初始化它们而尝试用“某物”来初始化它们。这绝对不会带来任何好处,并且实际上可能会产生负面影响。
请注意,一些现代开发工具(例如 MS Visual Studio 2005)将在代码的调试版本中捕获对未初始化变量的运行时访问。即,这些工具可以帮助您在变量有机会获得有意义的值之前检测到访问变量的情况,这表明代码中存在错误。但是对你的变量执行无条件的过早初始化,你基本上会扼杀工具的这种能力,并将这些错误扫到地毯下。
这个话题已经在这里讨论过:
http://www.velocityreviews.com/forums/t282290-how-to-initialize-a-char.html
它指的是 C++,但它也可能对您有用。
这个问题有几个很好的答案,其中一个已被接受。无论如何,我将回答以扩展实用性。
是的,将指针初始化为 NULL 以及在不再需要(即释放)指针后将指针设置为 NULL 是一种很好的做法。
在任何一种情况下,能够在取消引用之前测试指针都是非常实用的。假设您有一个如下所示的结构:
struct foo {
int counter;
unsigned char ch;
char *context;
};
然后,您编写一个应用程序,该应用程序产生多个线程,所有这些线程都通过使用互斥在单个分配的 foo 结构上(安全地)运行。
线程 A 在 foo 上获得一个锁,增加 counter 并检查 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() 更加危险,因为调用者会有一些安全错觉。除非您确定每个操作都是一致的,否则您不能依赖实践“批发”。
可能比您实际想要的信息多得多。
首选款式:
在 C 中:char * c = NULL;
在 C++ 中:char * c = 0;
我的理由是,如果您不使用 初始化NULL
,然后完全忘记初始化,那么由于此时内存中可能存在垃圾,因此在取消引用时您将在代码中遇到的各种错误将更加难以追踪。另一方面,如果您确实初始化为NULL
,大多数时候您只会得到一个segmentation fault
,考虑到替代方案,这会更好。
即使您不需要立即初始化变量,初始化变量也是一个好习惯。通常,我们将指针初始化为 NULL,将 int 初始化为 0,并将浮点数初始化为 0.0 作为约定。
int* ptr = NULL;
int i = 0;
float r = 0.0;
在 C++ 中初始化指针变量总是好的,如下所示:
int *iPtr = nullptr;
char *cPtr = nullptr;
因为如上所述的初始化将有助于以下条件,因为nullptr可转换为bool,否则您的代码最终将引发一些编译警告或未定义的行为:
if(iPtr){
//then do something.
}
if(cPtr){
//then do something.
}