C++低级错误

来源:互联网 发布:地图数据 编辑:程序博客网 时间:2024/06/05 00:25

1.  数组下标访问越界

2.  使用野指针

3.  内存拷贝忽略字符串结尾标志\0

4.  判断无符号数是否小于0

5.  循环变量数据类型太小

6.  循环体内改写循环变量

7.  混淆===

8.  函数局部变量或参数过大,堆栈溢出

9.  数据类型不一致,变量或参数赋值出错

10. 分支流程未释放动态申请的内存

代码案例:

1.   数组下标访问越界

(1)数组下标根据计算得出

i = a – b ;

array[i] = 0 ; //使用前应该检查i的合法性

 

(2)数组下标通过函数得出

void main()

{

int i, b[10];[1]

getIndex(&i);

    b[i] = 0;  //使用前应该检查i的合法性

}

 

(3)数组下标是循环变量

void main()

{

int i, max, b[10];

getMax(&max); 

for (i = 0; i < max; i++) //使用前应该检查max的合法性

{

     b[i] = 0;

}

}

2.   使用野指针

(1)使用未分配空间的指针

void func()

{

    char *p;

if (NULL != p)

{

         printf(“%s”, p);

    }

}

(2)内存空间释放后指针未置Null,内存指针仍被继续使用

void* g_pBuf = NULL;

void ATM_CellRecv(U8 *pBuf,U32 ulLen)

{

   g_pBuf = pBuf;//g_pBuf通过pBuf赋值指向内存区域

   ......

   if ( NULL != pBuf )

   {

        free(pBuf);//只是释放了内存,而g_pBuf并没有置成NULL.

   }

}

 

3.   内存拷贝忽略字符串结尾标志’\0’

void fun()

{

    char dest[10];

    char src[] = "0123456789";

    memcpy(dest, src, sizeof(src));

}

4.   判断无符号数是否小于0

unsigned char c;

//c赋值为具体的循环次数

while(c-->=0)

{

//do something…

}

5.   循环变量数据类型太小

unsigned char c;

unsigned short s;

//do something

//s > 255

for (c = 0; c < s; c++)

{

     //do something

}

6.   循环体内改写循环变量

unsigned long i;

for (i = 0; i < 1024; c++)

{

    for (i = 0; i < 512; c++)

    {

        //do something

    }

}

7.   混淆“=”“==”

如下例子的循环判断条件中,将”==”误写成”=”,导致死循环。

Bool result = True;

while(result = True)

{

result = execFunc();

wait();

}

编程规范要求将常量写在等号左边(如“True==result”),确保编译时即可发现错误。

8.   函数局部变量或参数过大,堆栈溢出

void Function(void) {

    char b[0x200000];

}

 

int main()

{

    ret = function();

}

函数参数的输入、输出如果是一个比较大的结构,要用指针带入保存输入数据的内存地址,用指针带入保存输出的内存地址,不要直接用值传递的方式输入和输出。如果函数的较大的输入输出使用值传递方式,对函数堆栈处理有较大的开销。当数据接近或者大于堆栈空间的时候,就会出现堆栈溢出错误

如果是使用DOPRA平台,可以在v_configkernel.h文件中找到默认的栈大小

#define VOS_DEFAULT_STACK_SIZE  0x200000

9.   数据类型不一致,变量或参数赋值出错

short int x;

int y;

void *p ;

p=&x;

*(int*)p=y;

    x只有两个字节的空间,而int需要4个字节的空间, 实际上己出问题了。还有一个例子,会导致入参被踩:

int func(short int s, int* pi)

{

    …//do something

*pi = 0;

return 0;

}

 

int main(int argc, char* argv[])

{

short int x;

short int y;

int iRet;

   

    …//do something

    x  = 1;

    iRet = func(x, (int *)&y);

}

调用函数func后, x = 0。

10.             分支流程未释放动态申请的内存

void Function1(int nSize)

{

char* p= (char*)malloc(nSize);

if( !GetStringFrom(p, nSize) )

{

MessageBox(“Error”);

      return;

}

…//using the string pointed by p;

free(p);

p = NULL;

}

当函数GetStringFrom()返回零的时候,指针p指向的内存就不会被释放。这是一种常见的发生内存泄漏的情形。程序在入口处分配内存,在出口处释放内存,但是c函数可以在任何地方退出,所以一旦有某个出口处没有释放应该释放的内存,就会发生内存泄漏。

 

内存分配方式有三种:

  (1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量,静态内存区。

  (2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

  (3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。应用程序一般使用malloc,realloc等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。



 

原创粉丝点击