一. 问题
最近在Debug模式下运行程序,“生成“的时候,输出窗口提示警告,所局部变量指针exparam没有初始化。关于局部变量的这部分代码如下图所示:
void Process_Property_Form::on_actionReadProperty_triggered()
{
SEQPARAM seqparam;
EXPERIENCE3D *exparam;
// 将局部变量指针expr初始化。
//exparam = NULL;
double TE = ui->TE->value();
double TR = ui->TR->value();
/*
tp->TI = ui->TI->value();
tp->FA = ui->FA->value();
*/
// 有关K空间和扫描视场的参数都属于场景参数。
int ntx = ui->ntx->value();
int nty = ui->nty->value();
int ntz = ui->ntz->value();
double tacq = 10.00;
double fovx = ui->fovx->value();
double fovy = ui->fovy->value();
double fovz = ui->fovz->value();
// 传个结构体,否则传递太多参数容易出错。
//emit processCompleted(timeparameter);
/* Sequence */ // 序列
SetSeqParamTE(&seqparam, TE);
SetSeqParamTR(&seqparam, TR);
SetAcqExperience(exparam, ntx, nty, ntz, tacq);
}
虽然是警告,但是在Debug下运行程序出错,出错代码所在代码块:
void SetAcqExperience(EXPERIENCE3D *expr, int ntx, int nty, int ntz,
double tacq)
{
expr->ntx = ntx;
expr->nty = nty;
expr->ntz = ntz;
Process_Property_Form::OutputDebugPrintf("expr->ntx = %d\n", expr->ntx);
Process_Property_Form::OutputDebugPrintf("expr->nty = %d\n", expr->nty);
Process_Property_Form::OutputDebugPrintf("expr->ntz = %d\n", expr->ntz);
if (tacq == 0)
{
fprintf(stderr, "Error : acquisition time equals zero\n");
Process_Property_Form::OutputDebugPrintf("出现错误,成像时间 等于 零\n");
exit(1);
}
else
{
expr->readout_time = tacq;
Process_Property_Form::OutputDebugPrintf("expr->readout_time=%f\n", expr->readout_time);
}
//expr->pt = expr->readout_time / (expr->ntx - 1);
//InitRFSigExperience(expr);
}
出错代码为上方函数体的第一行:expr->ntx = ntx;
然后我将指针初始化,即在上方第一块代码中:
// 将局部变量指针expr初始化。
exparam = NULL;
“生成”的时候不再警告,但是最后在Debug模式下运行代码,还是出错,出错位置不变。
二. 原因
我将指针初始化以后,它不再指向结构体,指针中不再存储结构体的地址,所以
expr->ntx = ntx;
这行代码中的expr->ntx有逻辑问题。
三. 解决方法
第一步:
将展示的第一块代码中的:
EXPERIENCE3D *exparam;
改为:
EXPERIENCE3D exparam;
第二步:
将展示的第一块代码中的:
SetAcqExperience(exparam, ntx, nty, ntz, tacq);
改为:
SetAcqExperience(&exparam, ntx, nty, ntz, tacq);
然后“生成”,在Debug模式下运行程序,程序均没有警告和错误。
四. 拓展
我在网上看到一篇有关该问题的文章,不过文章的作者是用VC++开发的,他的文章如下:
《编写高质量代码:改善C++程序的150个建议》本书是C++程序员进阶修炼的必读之作,包含的全部都是C++编码的最佳实践,从语法、编码规范和编程习惯、程序架构和设计思想等三大方面对C++程序和设计中的疑难问题给出了经验性的解决方案,为C++程序员编写更高质量的C++代码提供了150条极为宝贵的建议。本节为大家介绍建议5:不要忘记指针变量的初始化。
建议5:不要忘记指针变量的初始化
可以说指针是C/C++语言编程中最给力的工具。指针,让我们直接去面对最为神秘的内存空间,赋予我们对内存进行直接操作的能力。由于指针操作执行速度快、占用内存少,众多程序员对它深爱不已。但是,它的灵活性和难控制性也让许多程序员觉得难以驾驭,以致到了谈指针色变的程度。
指针就是一把双刃剑。用好了它,会给你带来诸多便利,反之,则往往会引发意想不到的问题。
其中,指针的初始化就是我们应当重视的问题之一。指针应当被初始化,这是一个毋庸置疑的问题,关键是应该由谁来负责初始化,是编译器,还是程序员自己?
为了更好地贯彻零开销原则(C++之父Bjarne在设计C++语言时所遵循的原则之一,即“无须为未使用的东西付出代价”),编译器一般不会对一般变量进行初始化,当然也包括指针。所以负责初始化指针变量的只有程序员自己。
使用未初始化的指针是相当危险的。因为指针直接指向内存空间,所以程序员很容易通过未初始化的指针改写该指针随机指向的存储区域。而由此产生的后果却是不确定的,这完全取决于程序员的运气。例如下面的程序片段:
#include <iostream>
int main()
{
int *pInt;
std::cout<<pInt<<"\n";
return 0;
}
在VC++中,程序在Release模式下输出0x004080d0,而在Debug模式下输出0xcccccccc。很明显未初始化的指针指向的是一个随机的地址。如果对其执行写操作会怎样?那很有可能会直接导致程序崩溃。
可以将指针初始化为某个变量的地址。需要注意的是,当用另一个变量的地址初始化指针变量时,必须在声明指针之前声明过该变量。代码片段如下所示:
int number = 0; // Initialized integer variable
int *pNumber = &number; // Initialized pointer
当然,我们在必要时也可以将其初始化为空指针0(NULL):
int *pNumber = NULL; // Initialized pointer as NULL
如果使用未初始化的局部变量,程序编译时会给出警告C4700:
warning C4700: 使用了未初始化的局部变量"**"
需要注意警告中的四个字“局部变量”。因为对于全局变量来说,在声明的同时,编译器会悄悄完成对变量的初始化。代码片段如下所示:
#include <iostream>
int *pInt;
int main()
{
std::cout<<pInt<<"\n";
return 0;
}
此时,程序编译不会再出现警告,程序输出:00000000。
请记住:
使用未初始化的局部指针变量是件很危险的事,所以,在使用局部指针变量时,一定要及时将其初始化。