C++的一些小问题总结

(1)指针修改常量区数据出错

char *s1 = "nonths";

char s2[] = "nonths";

这两句定义看起来一样,实则不然。*s1定义的字符串“nonths”是放在静态区的字符串常量,不能修改,如果我们用*s1 = 'x';去修改的时候就会导致程序崩溃;但是s2数组定义的nonths却是放在栈区的字符串变量,程序员可以修改,用s2[1] = 'x';来修改不会出错。切记!

(2)关于实例化一个类

加入存在一个DOG类,那么我要定义一个类对象,有两种方式:

DOG mydog;

DOG *p_mydog;

注意此时mydog已经调用DOG类的构造函数构造了一个mydog对象;但是p_mydog只是分配了一个地址,并没有构造一个DOG类的实例化对象,因为没有为它分配内存。

p_mydog = new DOG;只有执行这一句话后,才会为其分配内存,并调用DOG类的构造函数构造一个DOG类对象。

(3)关于内存对齐的问题

    所谓内存对齐就是指许多实际的计算机系统对基本数据类型在内存中存放位置的限制,它们会要求这些数据的首地址的值是某个数k(通常为4或者8)的倍数。这样的限制也是为了方便计算机的对数据的读写,如果内存不对齐,可能原本只需要一次内存访问就可以的,现在却需要两次内存访问。

    内存对齐的规则:每个特定平台上的编译器都有自己的默认“对齐系数”,程序员可以通过预编译命令#pragma pack(n),其中n=1,2,4,8,16来改变这一系数。

    规则:(1)数据成员对齐规则:结构体(struct)或共用体(union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照“对齐系数”和这个数据成员自身长度中,比较小的那个进行。(2)结构体或共用体的整体对齐规则:在数据成员完成各自对齐之后,结构体本身也要进行对齐,对齐按照“对齐系数”和结构体中最大数据成员长度中,比较小的那个对齐。

 

举例:以下均假设“对齐系数”为n=4

1、struct aa{

int a;    //取n=4和int长度4中最小的4对齐,也就是a的起始地址是4的倍数,占用地址【0,3】

char b;   //取n=4和char长度1中最小的1对齐,也就是b的起始地址为任意,占用地址【4】

char c;  //同上,c占用的地址为【5】

char d; //同上,d占用地址【6】

}

 所以成员占用的总大小为:7

根据整体对齐规则,数据成员中最大数据长度为4,整体按4对齐,即6对4取圆整为8;

所以这个数据结构占用的字节数即sizeof(aa)=8;

2、这个例子的数据成员和上面一样,只是定义顺序变化了我们再看一下:

struct aa{

char a;    //取n=4和int长度4中最小的4对齐,也就是a的起始地址是4的倍数,占用地址【0】

int b;   //取n=4和char长度1中最小的1对齐,也就是b的起始地址为任意,占用地址【4,7】

char c;  //同上,c占用的地址为【8】

char d;  //同上,c占用的地址为【9】

}

 

 所以成员占用的总大小为:10

根据整体对齐规则,数据成员中最大数据长度为4,整体按4对齐,即10对4取圆整为12;

所以这个数据结构占用的字节数即sizeof(aa)=12;

 

从上面的两个例子我们就看到由于结构体中定义变量顺序的不同而导致结构体占用的字节数的不同,这都是因为内存对齐引起的。

有人可能会问一个问题,为什么到最后要来一个整体对齐呢?好,那我们先假设我们要定义一个aa结构体的数组,那么考虑到C标准保证,任何类型(包括自定义结构类型)的数组所占空间的大小一定等于一个单独的该类型数据的大小乘以数组元素的个数。加入我定义一个结构体数组bb[2],如果我们不用整体对齐,第二个结构体的长度就是10,那么bb[1]的长度是[0,9],bb[2]的地址从10开始,这是你再计算一下结构体的长度就是8,而不是10了。所以需要考虑整体对齐,是为了方便数组的定义。

 

(4)关于引用

引用就是给一个变量取一个别名,引用和原变量完全一样,就连他们的地址都是一样的,引用必须在定义时初始化,而且引用一个变量以后它移植到程序结束都是那个变量的别名,不能修改为另一个变量的别名。

int a;

int &ya = a; //&不是取地址,而是引用符号

一般函数的传递方式为值传递,也就是说子函数里面对数据的修改不会体现在主函数里面,但是引用可以解决这个问题。

假如定义一个交换两个数据的函数:

void swap(int a,int b)那么这个函数执行以后主程序中的a,b都没变。

void swap(int &a,int &b)那么这个函数执行以后主程序中的a,b交换,因为引用就是原变量本身。

 

(5)关于默认构造函数

如果我们创建一个对象,没有创建构造函数,那么编译器会自动给我们添加一个默认构造函数(不带参数,函数体不执行任何操作)。假如我们已经创建了一个构造函数,不管这个函数带参数还是不带参数,编译器都不再为我们提供默认构造函数。也就是说假如我们自己创建了一个带参数的构造函数,但是我们还想用一个不带参数的构造函数,那么这个不带参数的构造函数必须由我们自己定义。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值