20170215C语言提升08_指针_02数组指针及指针数组及函数指针
2017-02-15 18:54
567 查看
数组指针:
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; }
复习:
bc99
相关文章推荐
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170215C语言提升08_指针_02数组指针及指针数组及函数指针
- 20170214C语言提升08_指针_01变量及指针及数组
- 20170214C语言提升08_指针_01变量及指针及数组
- 20170214C语言提升08_指针_01变量及指针及数组
- C语言02 - 指针运算、数组与指针、指针变量名、指针与函数参数、指针函数、函数指针、二级指针
- 20170214C语言提升08_指针_01变量及指针及数组
- 20170214C语言提升08_指针_01变量及指针及数组
- 20170214C语言提升08_指针_01变量及指针及数组
- 20170214C语言提升08_指针_01变量及指针及数组
- 20170214C语言提升08_指针_01变量及指针及数组
- 20170214C语言提升08_指针_01变量及指针及数组
- C语言 复杂指针的申明问题 数组指针 指针数组 函数指针 指针函数一览无遗! C/C++求职面试必备考点(四)
- C语言之指针、数组和函数