(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)关于内存对齐的问题
举例:以下均假设“对齐系数”为n=4
1、struct aa{
int a;
char b;
char c;
char d; //同上,d占用地址【6】
}
根据整体对齐规则,数据成员中最大数据长度为4,整体按4对齐,即6对4取圆整为8;
所以这个数据结构占用的字节数即sizeof(aa)=8;
2、这个例子的数据成员和上面一样,只是定义顺序变化了我们再看一下:
struct aa{
char
int
char c;
char d;
}
根据整体对齐规则,数据成员中最大数据长度为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)关于默认构造函数
如果我们创建一个对象,没有创建构造函数,那么编译器会自动给我们添加一个默认构造函数(不带参数,函数体不执行任何操作)。假如我们已经创建了一个构造函数,不管这个函数带参数还是不带参数,编译器都不再为我们提供默认构造函数。也就是说假如我们自己创建了一个带参数的构造函数,但是我们还想用一个不带参数的构造函数,那么这个不带参数的构造函数必须由我们自己定义。