1:一维数组:数组名相当于当前类型的一个指针,而且为const的指针,指向(指针里面的内容)不可变。
2:一维数组和二维数组的内存分布是完全一样的,但是还是有不同。首地址+1的时候,一位数组加的数组类型的大小,二位数组加的是第二维大小*数据类型大小(类型为数组类型)。#include <stdio.h>int main(){ int array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int other[2][5] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; PRintf("%p/t%p/n", array, array + 1); //后者 +1*sizeof(*array) = +4 printf("%p/t%p/n", other, other + 1); //后者 +1*sizeof((*array)[5]) = +20 return 0;}3:上面二维数组的时候用数组名+1实际上是加上数组类型的大小。在以为数组名前面加&符号得到的实际上也是数组类型。
注意:数组类型实际上是由两个因素决定的:
1:元素类型 2:数组大小。任何一个数组都存在其数组类型。
下面是数组指针的用法: int array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int (*parray)[10] = &array; //前面的就是数组指针,它指向的是数组类型 printf("%p/t%p/n", parray, parray + 1); //这里 +1 实际上是 + 1*sizeof(*(parray[10])) = +40;
4:平时使用数组指针不会像上面这种方式定义。可以使用typedef来定义。
#include <stdio.h>typedef int (INT10)[10]; //数组类型int main(){ int array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int other[2][5] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; printf("%p/t%p/n", array, array + 1); //后者 +1*sizeof(*array) = +4 printf("%p/t%p/n", other, other + 1); //后者 +1*sizeof(*(array[5])) = +20 int (*parray)[10] = &array; //前面的就是数组指针,它指向的是数组类型 printf("%p/t%p/n", parray, parray + 1); //这里 +1 实际上是 + 1*sizeof(*(parray[10])) = +40; INT10 *intarray = &array; printf("%d/n", sizeof(INT10)); //40 printf("%p/t%p/n", intarray, intarray + 1); //+1 = +40byte return 0;}5:数组指针两个比较重要的因素:元素类型,数组大小
注意:定义数组指针的时候,数组大小必须要吻合(warning C4048: “int (*)[5]”和“int (*)[10]”数组的下标不同),类型也应该吻合(warning C4133: “初始化”: 从“int (*)[10]”到“char (*)[10]”的类型不兼容),否则会产生警告。
6:二维数组里面的第一个维度相当于就是存储的数组指针,他们指向的是多个以而为下标大小的数组类型。+1也就是加的二维的大小。
下面的代码可以更好的让我们理解数组指针:
#include <stdio.h>void foo(int (*array)[10]) //定义成数组指针,这样才是接收常量数组指针最正确的方式。二维的写两个[][]。{}int main(){ int array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int other[2][5] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };// foo(array); //array -> 常量指针(int * const)// foo(other); //other -> 常量指针(int(*)[5]) foo(&array); //&array -> 常量数组指针(int(*)[10])// foo(&other); //&other -> 常量数组指针(int(*)[2][5]) return 0;}指针数组:
1:指针数组就是存放指针的数组,很好理解。一个数组,它里面有很多个指针。#include <stdio.h>int main(){ char *key1s[10] = { "aaa", "bbb", "ccc" }; //这种就是指针数组,就是一个存放指针的数组。 //上面这个指针数组可以存放10个字符指针,字符串可以存放的长度和这个没有任何关系。字符串有多长和指针无关。 char key2s[100][100] = { 0 }; //这里面可以存放(管理)100个字符串,能够存放的字符串长度可以是10000(-1)。 return 0;} 注意:上面程序的key1s和key2s的区别:key1s是只可读的,key2s是可读写的。key1s为指针数组,key2s为字符数组,C语言是没有字符串类型。2:不同初始化方式保存的位置以及是否可改:#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>#include <string.h>int main(){ char *key1s[10] = { "aaa", "bbb", "ccc" }; //这种就是指针数组,就是一个存放指针的数组。 //上面这个指针数组可以存放10个字符指针,字符串可以存放的长度和这个没有任何关系。字符串有多长和指针无关。 char key2s[100][100] = { 0 }; //这里面可以存放(管理)100个字符串,能够存放的字符串长度可以是10000(-1)。// 指针可改? 数据可改? //堆区: char *str1 = malloc(100 * sizeof(char)); //可改 可改 //栈区: char str2[100]; //不可改 可改 //常量区: char *str3 = ""; //可改 不可改 char *str4 = str1; strcpy(str4, "100"); //可改 正确操作 char *str5 = str3; strcpy(str5, "100"); //不可改 错误操作 在常量区 char *str6 = str2; str6[10] = '1'; //可改 正确操作 return 0;}3:指针数组的参数传递实际上是传递的指针的指针。传参为二级指针。#include <stdio.h>void foo(char *key[])//传递过来的是指针数组的首元素地址。是拷贝过来的。{ printf("%s/n", key[1]);//bbb printf("%s/n", key[2]);//ccc printf("%s/n", key[3]);//<null> char *str = "123456"; key[1] = str; printf("%s/n", key[1]);//123456}int main(){ char *key1s[10] = { "aaa", "bbb", "ccc" }; foo(key1s); //key1s 首元素类型 char** //&key1s 数组指针 char*(*)[10] 指针数组的数组指针 return 0;}4:指针数组在main函数里面就有运用,真实的main函数织机上是这样的:#include <stdio.h>//main函数实际上为操作系统调用。操作系统默认会传递几个参数进去。int main(int argc, char* argv[], char* env[])//argc是argv的数量,argv是操作系统传递的参数,env是环境变量。{ for (int i = 0; i < argc; ++i) { printf("%s/n", argv[i]); } //操作系统传递的参数一是文件路径。 //还可以在exe的快捷方式里目标的最后加上字符串 也可以传递进来。 //还可以通过cmd执行的时候,在后面加上一些参数 int i = 0; while (env[i] != NULL) { printf("%s/n", env[i++]); } return 0;}函数指针:
1:函数也有自己的类型,函数指针主要用于做回调函数以及函数的路由等。#include <stdio.h>int Foo(int one, int two)//函数类型是 int(*pfoo)(int, int){ return one + two;}void Foo2()//函数类型是 void(*pfoo2){}typedef int FOOTYPE(int, int);//可以定义函数类型,int main(){ void *pFoo = &Foo; int(*pfoo)(int, int) = Foo;//int(*pfoo)(int, int) = &Foo;//这里加&和不加&是完全一样的,这里与变量不一样。 void(*pfoo2) = Foo2;// printf("%d/r/n", pFoo(1, 2)); //不知为什么出错 printf("%d/r/n", pfoo(1, 2)); FOOTYPE *p = &Foo; //使用typedef定义的类型来申请指针。 printf("%d/r/n", p(2, 3)); return 0;}2:typedef定义的函数类型是可以当作参数来使用的,能够在外部来传递,调用指定的方法#include <stdio.h>typedef int FOOTYPE(int, int);//可以定义函数类型int Foo(int one, int two)//函数类型是 int(*pfoo)(int, int){ return one + two;}void Foo2()//函数类型是 void(*pfoo2){}typedef void (FUNCERROR)(int);void PrintError(int code){ printf("Error: %d", code);}void SetValue(char*array[], char*value, FUNCERROR *error){ if (array == NULL) error(100);}int main(){ void *pFoo = &Foo; int(*pfoo)(int, int) = Foo;//int(*pfoo)(int, int) = &Foo;//这里加&和不加&是完全一样的,这里与变量不一样。 void(*pfoo2) = Foo2;// printf("%d/r/n", pFoo(1, 2)); //不知为什么出错 printf("%d/r/n", pfoo(1, 2));//可以看出调用和普通的函数调用区别不大 FOOTYPE *p = &Foo; //使用typedef定义的类型来申请指针。 printf("%d/r/n", p(2, 3)); SetValue(NULL, NULL, PrintError);//会打印error: 100 return 0;}复习:
新闻热点
疑难解答