您的位置:首页 > 编程语言 > C语言/C++

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息