1.数组可以有多维数组。c99支持动态数组,c11和c99之前不再支持。
2.数组 初始化一个后,后面的自动初始化为0,如果不初始化,都是垃圾值。
3.数组初始化 可以指定 ss[10]={0,2,3,[2]=3,};。通过[x]可以指定x位置数组初始化,如果该位置已经初始化,将被替换。
4.对于指针的理解。指针非常简单易用。指针有类型,比如char int long float 等,这是指指针指向的数据是char int long等,而指针本身是一种全新的类型,不在普通类型范围内。比如printf要使用 %p来显示指针地址。定义一个指针 char *p; *与p之间可以保持一个空格,也可以紧挨着。使用中我们经常使用 char a=0; p=&a; 将a的物理内存地址赋值给 p指针内,我们可以把指针比作一个存放其他数据内存地址的容器(碗?)。* p 的*指的是地址翻译器(间接运算符),它可以将p指针内指向的数据翻译出来。
5.对于指针指向数组,ss[10]={0};p=ss; p == ss[0] 也就是说 等同于指向数组第一个数据位置ss[0]的地址。
6.*(p+1),*(p+2),*(p+3),指的是什么? +1 +2 +3并不是指内存地址 +1 +2 +3,而是指 指向的数据 +1 +2 +3,如果是char型数据,代表着移动1 2 3个char型数据,如果是int指针,代表着移动1 2 3个int数据地址,这就是为什么指针还有类型,是为了方便准确的翻译数据与地址的关系。这种用法有直接 p++ ; p+=x;等直接改变指针的做法,还有*(p+x)等做法,各有优点。
7.指针的优势,c语言里面,非常灵活的应用于函数内改变数据,因为传递到函数的实际的物理内存地址,所以函数内能够抓取到传递的数据的真身,在内存中修改它。而普通形参传递的只是临时数据转换,并不能改变原有的数据。当然数组、结构体也是与内存实际相关的,他们在内存中是依次顺序排列的,这就为一些神奇操作创造了条件,比如快速的格式化一组结构体,寄存器,数据结构等等,也就是说指针操作对象是真实的内存,与机器更接近一点。(其他高等语言可能没有,可能不一样,另外对于有mmu内存管理单元的cpu来说,c语言操作的却是存在于镜像之上的虚拟实际内存地址)
8.const 指针可以指向非const 和 普通数据,非const的数据赋值给普通指针。形参可使用const修饰,既可以保护数据,又可以同时处理 const和非 const数据。
9.指针和数组的关系,a[] 和普通指针很相似,操作一维数组和操作普通指针没有太大区别。char (* pz)[2] ptr是一个指向一个数组的指针,这个数组里面包含两个 char数据.
1 char ss[4][2]={{2,4},{6,8},{1,3},{5,7},};
2 ss[0][0]=2;
3 * ss[0]=2;
4 *(*ss+1)[0]=6;
5 **ss=2;
6 *(*(ss+2)+1)=3;
7 pz=ss;
8 *(*pz+1)=6;
9 pz[0][0]=2;
10 *pz[0]=2;
11 **
10.指针兼容性较差,不同类型的指针不能相互转换。
1 典型例子:
2 int * pt;
3 int(*pa)[3];
4 int ar2[3][2];
5 pa=ar2;
6 p2=&pt;
7 *p2 = ar2[0]; //有效*pa和ar2[0]都是指向整数的指针。
8 p2 =ar2;//无效 p2指向指针的地址 ar2指向数组的指针。
9 --把非const指针赋值给const指针是不安全的,会有警告,执行这样的代码是无效的,你可能会试图更改const指针指向地址的数据,但这是无效的,改地址不允许被改变。
10
11 典型例子;
12 const int **pp2;
13 int *p1;
14 const int n=13;
15 pp2=&p1;//非const指针赋值给const,会有警告,不能通过*pp2修改它所指向的内容。
16 *pp2 = &n;//有效,两者都是const,但是试图通过 *pp2来改变它所指向内容是不允许的 *pp2所指向的是指针p1,试图将改变p1指针内容
17 *p1=10;//有效但是 n得知不会改变,编译的结果也不可信,可能是10 可能是13 在不同编译环境不同。
11.变长数组,在 c99增添了变长数组,也就是允许出现 临时变量、变量来初始化数组, 1 int a=10, 2 b=5; 3 double ss[a][b]; 这种属性在某些函数具有数组形参 定义的情况下,可以提高函数的容纳性,也就是一个函数就可接受各种长度的数组,但是以前的指针也可以实现。该属性在c11中被保留,但是需要开启才能用。
12.复合字面量,int diva[2]={10,20};(int [2]){10,20}//复合字面量 该种类型主要用于初始化 指向数组的指针,初始化要一气呵成。 int * pt1; pt1=(int [2]){10,20};
13.一个指向字符串的指针ss,ss[1]=’1’;//? 这样会导致什么问题呢? 由于编译器的优化,将导致 不管你定义多少字符串 “hello world !”,如果该字符串倍多次引用,但是编译器为了节省内存(flash),将用一个字符串代替所有出现改字符串的位置(也就是不管谁用,都将调用同一个内存位置的同一个字符串)。这时候如果你更改了 ss[1]=’a’;那么即便后面出现的 printf(“hello world”);//将会打印出 hallo world ! 有些编译器的行为将变得难以捉摸,程序甚至崩溃。所以键入你要使用 指针指向字符串,那么请使用const修订符。
14.字符串数组:
1 const char * ss[5]={ //其实指的是 ss内部有五个 指针 也就是常说的面试题 定义一个有x个指针的数组
2 //特点 占用字节少 系统共占用 5x8=40字节 (指针占用 8个字节?) 其中字符串字面量倍储存在静态变量(对于嵌入式系统,存储在flash里面)。字符串不一定连续储存在内存中
3 "adding number",
4 "adding number",
5 "adding number",
6 "adding number",
7 "adding number",
8 }
9
10 char ss[5][20]={ //这个是包含五个字符串的数组和二维数组一样
11 //前面说过,c系统为了节省资源,整个程序出现的字符串,都将使用一个代替,数组有点不同,数组使用副本,就是重新copy一份,这样就是会占用两份资源。另外字符串分配资源利用率也很低,不管用没有,
//每个字符串将被分配20个字节。几个字符串连续储存在内存中
12 "adding number",
13 "adding number",
14 "adding number",
15 "adding number",
16 "adding number",
18 }
对比:使用指针字符串不能更改 对于字符串要一直更改的场合请使用字符串数组。