您的位置:首页 > 编程语言 > C语言/C++

c++新手容易犯的几个错误

2014-05-10 16:41 267 查看
1.不清楚unsigned类型的特性
#include <string.h>

#include <stdio.h>

int  main( )

{

 char* str = "Hellow"; 

 for (int i = 0; strlen(str)-i>=0; i++)//死循环

 {

  printf("%d \n",i);

 }

 return 0;



上面的程序会出现死循环。看似正确的程序,为什么会出现死循环呢。因为strlen()的返回值是unsigned int类型。unsigned int与int类型相减得到的也是unsigned int类型unsigned int是永远>=0的,所以上面的程序出现了错误。我们在与unsigned 类型变量做大小比较的时候要注意,unsigned 类型>=0永远为真.所以unsigned的类型尽量不要跟0比较大小,上面的判断可以改成i<=strlen(str)

2.返回指向栈空间数据的指针。
#include <string.h>

#include <stdio.h>

char* IntToString(int n)

{

 char strName[64];

 sprintf(strName, "%d", n);

 return strName;//返回的是栈空间的地址,函数返回后 栈空间数据会被释放。

}

int  main( )

{

 int n = 100;

 char* str =  IntToString(n);

 printf("%s", str);

 return 0;



上面的例子将不会打印“100”。第一次看的这个问题,是林锐博士写的《高质量程序设计》里面的一个例子。IntToString()函数里面定义的char strName[64]; 定义的数据是保存在栈空间,函数返回后,栈空间数据会被释放。那么函数返回的指针就是一个野指针。指向了一个无效地址。使用这个指针的时候就会出现问题。上面的函数可以改成char* IntToString(char* bufOut, int n);通过参数传递一个栈外面的申请的空间地址。或者在IntToString()里面new一个堆空间的地址。

3.对包含有string 的结构体里清零。
#include <string>

#include <stdio.h>

using namespace std;

typedef struct  

{

 int n;

 string str;

}DATA;

int  main( )

{

 DATA d;

 memset(&d, 0, sizeof(DATA));// 你知道sizeof(DATA)为多少不?

 return 0;



上面这个例子在windows下编译运行成功,但在linux下会运行错误。我们经常会给一个结构体清零,如果这个结构体里面含有string,那么这个结构体的sizeof()将不能正确反映这个结构体占用的内存大小。我做过这样的实验,sizeof(string)的值 在32位 linux下等于4, 在vc++6.0下等于16,而在vc++ 2005下面等于32。这些值和编译器有关,而且不能反映string数据大小。所以我建议在结构体里面,不要定义string、 CString等不固定大小的类型。

4.指针类型强制转换。
#include <string>

#include <stdio.h>

using namespace std;

void Change(int* n)

{

 *n = 30;

}

int  main( )

{

 char a = 10;

 char b = 20;

 Change((int*)&a);//VC++6.0 release模式运行报错

 

 return 0;



上面的程序在32位 vc++6.0 debug下运行正常,但在release下运行报错。因为char类型变量的内存大小是1个字节,在Change函数里面将指向一个字节的指针转换成了指向4个字节的int*,赋值的时候把它指向的4个字节都改变了,也就是说把变量数据之外的数据也修改了,导致错误发生。那么debug模式为什么运行正常呢,笔者把a,b的地址打印出来,发现debug下a, b内存空间申请的是4个字节,和int型的一样大。第一个字节是char的值,后面三个字节是0xCC,这3个0xCC是debug模式为了方便检查内存溢出故意添加的。所以强制转换成int*也没有问题。鉴于上面问题,我们在指向空间大小不同的指针相互转换,一定要注意是否溢出。

5.char和int转换的问题。

#include <stdio.h>

int  main( )

{

 int n = 130;

 char c = n;

 int m = c;

 

 if (n == m)

 {

  printf("m==n \n");

 }

 else

 {

  printf("m!=n \n");

 }



上面的程序会打印m!=n。上面的例子里面 c==m为真 c==n为假 m==n为假。char c=n;执行完这条语句的时候,c的值就不是130了,因为c是有符号的,值为-126了。int m=c;执行完后m的值也是-126了。

童靴们在char int类型相互转换的时候,如果用unsigned char 代替char 就没这个问题了。

6.delete 和delete[] 的用法。

#include <stdio.h>

#include <string>

class A

{

public:

 A()

 {

  printf("A");

 }

 ~A()

 {

  printf("~A");

 }

};

int  main( )

{

 A* p = new A[3];

 delete p;//应该改为delete[] p;

 

 getchar();

 return 0;



上面的例子构造方法调用了3次,而析构方法只调用了1次. C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]。 关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间;(2) 为自定义类型分配和回收空间。 对于 (1),上面提供的程序已经证明了 delete[] 和 delete 是等同的。但是对于 (2),情况就发生了变化。基本本类型的对象没有析构函数,所以回收基本类型组成的数组空间用
delete 和 delete[] 都是应该可以的;但是对于类对象数组,只能用 delete[]。对于 new 的单个对象,只能用 delete 不能用 delete[] 回收空间。 所以一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用

7.传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的

否则报错*** glibc detected *** ./out: realloc(): invalid old size: 0x080486d0 ***
#include <stdio.h>

#include <stdlib.h>

#include <string.h>

void TestMem(void)

{

 char* page;

 char* temp;

 char* line = "test1";//此行改成下面注释的就OK了

 //char*  line = malloc(10);  strcpy(line, "test1");

 

 printf("line1=%X\n",line);

 if(temp=realloc(line, 1024))

 { 

  page=temp;

  printf("realloc [OK]\n");

 }

 strcpy(page, "test22");

 printf("line2=%X,page=%X\n",line,page);

 printf("line=%s,temp=%s,page=%s\n", line, temp, page);

 //free memory later

}

int main()

{

 TestMem();

 printf("main [OK]!\n");

 getchar();

 return 0;

}

realloc使用总结
        1. realloc失败的时候,返回NULL
  2. realloc失败的时候,原来的内存不改变,不会释放也不会移动
  3. 假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址
  4. 如果size为0,效果等同于free()
  5. 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的
  6.传递给realloc的指针可以为空,等同于malloc。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: