C/C+++结构体和多维数组的理解,希望大家批评指正。
结构体
本质
其实就可可以看做是一个普通类型(int),做函数参数时,也是值得传递。
定义和使用
struct x1 { ...}; 和 typedef struct { ...} x2; struct x1 { ...}para1,para2;
区别 : 第一种形式声明了一个 “结构标签”;
第二种声明了一个 “类型定义”。
第三种是定义了2个结构的变量1和变量2。
主要的区别是在后文中你需要用 “struct x1” 引用第一种, 而用 “x2” 引用第二种。也就是说, 第二种声明更像一种抽象类新 —– 用户不必知道它是一个结构, 而在声明它的实例时也不需要使用struct 关键字。
内存大小
为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。
1、在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。
2、VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
#include <stdio.h>
#include <string.h>
typedef struct
{
char d1;
char d2[5];
int d3;
}dog; // size 12,结构成员是数组,则类型为数组元素的类型
typedef struct
{
int c1;
char c2[5];
int c3;
}cat; // size 16,结构成员是数组,则类型为数组元素的类型
int main(int argc, char *argv[])
{
dog dd;
cat cc;
printf("size of dog:%d\nsize of cat:%d\n",sizeof(dd),sizeof(cc));
}
类型 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char 偏移量必须为sizeof(char)即1的倍数
int 偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
Short 偏移量必须为sizeof(short)即2的倍数
初始化(整体)
struct s
{
int l;
char* p;
};
int main(int argc, char* argv[])
{
struct s s1 = {.l=4, .p = "abcd"};
struct s s2 = {l:4, p:"abcd"};
return 0;
}
结构体注意
1、结构体中嵌套第三方提供的DLL库中的结构体时,需要重新编译相关的代码。
struct base
{
int n;
};
struct s
{
struct base b;
int m;
};
现在假设第一个结构是第三方提供的,第二个结构是你自己的。第三方提供的库是以DLL方式分发的,DLL最大好处在于可以独立替换。但随着软件的进化,问题可能就来了。
当第三方在第一个结构中增加了一个新的成员int k;,编译好后把DLL给你,你直接给了客户了。程序加载时不会有任何问题,在运行逻辑可能完全改变!原因是两个结构的内存布局重叠了。解决这类错误的唯一办法就是全部重新编译相关的代码
数组
数组名和&数组名区别
数组名的值只是一个指针常量,不能被修改(指针的值),数组名表示数组的首元素地址(等价与&数组名[0]),对数组的数组名做&操作则是整个数组的地址。
eg:
int arrys[10] = {0};
printf("arrys:%d arrys+1:%d \n",arrys,arrys+1);
printf("&arrys:%d &arrys+1:%d \n",&arrys,&arrys+1);
输出:
arrys:2293520 arrys+1:2293524
&arrys:2293520 &arrys+1:2293560
多维数组的数组名和&数组名理解:
一维数组: 数组名 数组的首元素首地址 ,&数组名 整个数组的首地址
多维数组: 数组名 一维数组的首地址 ,&数组名 整个数组的首地址
证明如下:
一维数组: 数组名 数组的首元素首地址 ,&数组名 整个数组的首地址
int main(int argc, char *argv[])
{
int arr1[2];
printf("arr1:%d arr1+1:%d\n",arr1,arr1+1);
printf("&arr1:%d &arr1+1:%d\n",&arr1,&arr1+1);
}
输出:
arr1:2686784 arr1+1:2686788 相差:4字节
&arr1:2686784 &arr1+1:2686792 相差:8字节=2*4
二维数组: 数组名 一维数组的首地址 ,&数组名 整个数组的首地址
int main(int argc, char *argv[])
{
int arr1[2][3];
printf("arr1:%d arr1+1:%d\n",arr1,arr1+1);
printf("&arr1:%d &arr1+1:%d\n",&arr1,&arr1+1);
}
输出:
arr1:2686752 arr1+1:2686764 相差:12字节=3*4
&arr1:2686752 &arr1+1:2686776 相差:24字节=2*3*4
三维数组: 数组名 一维数组的首地址(包含后面的二维和三维数组) ,&数组名 整个数组的首地址
int main(int argc, char *argv[])
{
int arr1[2][3][4];
printf("arr1:%d arr1+1:%d\n",arr1,arr1+1);
printf("&arr1:%d &arr1+1:%d\n",&arr1,&arr1+1);
}
输出:
arr1:2686688 arr1+1:2686736 相差:48字节=3*4*4
&arr1:2686688 &arr1+1:2686784 相差:96字节=2*3*4*4
四维数组: 数组名 一维数组的首地址(包含后面的二维、三维和四维数组) ,&数组名 整个数组的首地址
int main(int argc, char *argv[])
{
int arr1[2][3][4][5];
printf("arr1:%d arr1+1:%d\n",arr1,arr1+1);
printf("&arr1:%d &arr1+1:%d\n",&arr1,&arr1+1);
}
输出:
arr1:2686304 arr1+1:2686544 相差:240字节=3*4*5*4
&arr1:2686304 &arr1+1:2686784 相差:480字节=2*3*4*5*4
N维数组: 数组名 一维数组的首地址(包含后面的二维、三维......N-1维数组) ,&数组名 整个数组的首地址
数组参数等效的指针参数理解:
数组参数 等效的指针参数
一维数组 char a[30] 指针:char *a
指针数组 char *a[30] 指针的指针:char **a
二维数组char a[10][30] 数组的指针:char (*a)[30]
数据类型 * 指针名 其实就是告诉编译器,这个指针指向一个什么数据类型的内存,在对指针操作时,可以知道其指向的内存占用多少内存,但是指针本身是4个字节(sizeof)。
来源:oschina
链接:https://my.oschina.net/u/1783725/blog/625044