您的位置:首页 > 其它

数组指针,指针数组和函数指针

2017-06-08 22:51 169 查看
数组指针:首先呢他是一个指针,他有能力指向一个数组。

指针:其数值为地址的变量。

int (*p)[3]; // p首先与*结合,所以他呢是一个指针,他可以指向一个数组,这个数组有三个元素,每个元素为整形。


指针数组:首先呢他是一个数组,他的每一个元素为一个指针。

数组:由一系列类型相同的元素构成。

int *p[3]; // []的优先级高于 *,所以p首先是一个数组,这个数组有三个元素,每个元素为一个指针。


可以看出 p与谁先结合决定了他的类型是什么。

[] 的优先级高于*;() 的优先级高于[];

详解:

(1):数组在内存中的表示

创建一个数组,就是在内存中开辟了一块连续的空间。

二维数组是特殊的一位数组。

int main()
{
int a[2][2]={1,2,3,4};//这是一个2*2的二维数组
int (*p)[2];//数组指针
p=a;//令p指向数组a
return 0;
}


int (p)[2];[b]p首先与‘’[/b] 结合,所以p是一个指针,他可以指向一个数组,这个数组有两个元素。

(2)理解数组名和数组指针变量

a是一个数组名,类型是指向一维数组的指针,不是变量,a的值是指针常量,即不能有a++或者a=p这些操作。a指向这块连续空间的首地址,值是&a[0][0]。

a[0]是一维数组名,类型是指向整型的指针,值是&a[0][0],这个值是一个常量。

a[1]是一维数组名,类型是指向整型的指针,值是&a[1][0],这个值是一个常量。

p是一个数组指针变量,指向一维数组的指针变量,值是&a[0][0]。可以执行p++;p=a等操作。

a+1是取出第一行的首地址。

*(a+1)表示指向下一行元素,也可以理解为指向下一个一维数组。

a[0]+1是指向第0行第1个元素,也可以理解为指向一维数组a[0]的第一个元素。

p+1a+1

(p+1)(a+1)

虽然a跟a[0]值是一样,但类型不一样,表示的意义不一样。通过分析就不难理解为什么((a+i)+j)和a[i][j]等效了。

#include <stdio.h>

int main()
{
int a[2][2] = { 1, 2, 3, 4 };
int(*p)[2];
p = a;

printf("a = %p, p = %p, &a[0][0] = %p\n", a, p, &a[0][0]);

system("pause");
return 0;
}


输出结果一致,数值均为数组首元素地址。

(3)利用指针便利数组

#include<stdio.h>
#define M 2
#define N 3

int main()
{
int a[M]
= { 1, 2, 3, 4, 5, 6 };
int *start = &a[0][0];
int * const end = start + M*N;
for (; start != end; start++)
printf("%-5d", *start);
putchar('\n');
system("pause");
return 0;
}


输出结果

1 2 3 4 5 6

用指针遍历一个二维数组,同时也可以说明二维数组其实就是连续的一维数组。

(4)数组名与数组指针变量的区别

从(2)中的分析中得出数组名是指针,类型是指向元素类型的指针,但值是指针常量,声明数组时编译器会为声明所指定的元素数量保留内存空间。

数组指针是指向数组的指针,声明指针变量时编译器只为指针本身保留内存空间。

#include<stdio.h>
int main()
{
int a[2][2] = { 1, 2, 3, 4 };
int(*p)[2];//数组指针
p = a;//令p指向数组a
printf("%d\n%d\n", sizeof(a), sizeof p);
system("pause");
return 0;
}


输出结果:

16

4

sizeof() :关键字,并非函数,其作用为返回一个对象或者类型所占的内存字节数。

有输出结果可以看出**size(数组名)代表整个数组**4个int

指针p为一个地址

#include<stdio.h>

void main()
{
int a[2][2]={1,2,3,4};
int (*p)[2];
p=a;
printf("%d\n%d\n",sizeof(a+1),sizeof(p+1));
printf("%d\n%d\n",sizeof(a+0),sizeof(p+0));
printf("%p\n%p\n", a + 1, p + 1);
printf("%p\n%p\n", a + 0, p + 0);
}


输出结果



可见,a+i 变成为一个指针常量,

a+1 与 p+1 取到的地址也是相同的。

#include<stdio.h>

void f(int a[][2])
{
printf("%d\n", sizeof a);
}
int main()
{
int a[2][2] = { 1, 2, 3, 4 };
printf("%d\n", sizeof a);
f(a);
system("pause");
return 0;
}


输出结果

16

4

传参的时候数组名转化成指针变量,注意到函数f中f(int a[][2])这里并不需要指定二维数组的长度,此处可以改为int (*a)[2]。所以传过来的就是一个数组指针变量。

总结:数组名单独出现在sizeof内部时代表整个数组,具体看以前博客。(a+1)的类型是一个指针变量。把数组名作为参数传递的时候实际上传递的是一个指针变量。sizeof对变量和数组名操作时返回的结果会不一样。数组指针是指向数组的指针,其值可以是变量。

指针数组

(1)指针数组简单认识

指针数组:存放指针的数组

#include<stdio.h>

int main()
{
int i = 1, j = 2;
//p先跟[]结合,然后再跟*结合
int *p[2];//指针数组,存放指针的数组
p[0] = &i;
p[1] = &j;
printf("%d", sizeof(p));
system("pause");
return 0;
}


输出结果

8

首先呢p为一个数组,有两个元素,每个元素为一个整形指针。2*4

(2)多维数组与多级指针

A:二维数组

#include <stdio.h>

int main (void)
{
int a[3][2] = {{0, 1}, {2, 3}, {4, 5}};
int *p;
p = a[0];
printf ("%d\n", p[0]);
system("pause");
return 0;
}


输出结果

0

#include <stdio.h>

int main(void)
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf("%d\n", p[0]);
system("pause");
return 0;
}


输出结果

1

分析上述代码初始化部分

int a[3][2] = {{0, 1}, {2, 3}, {4, 5}};

int a[3][2] = {(0, 1), (2, 3), (4, 5) };

第一个为常见的初始赋值;

第二个则是一个逗号表达式,等价于 int a [3][2]={ 1, 3, 5};不完全的初始化赋值。

考虑存储大小:

#include <stdio.h>

int main (void)
{
int a[3][2] = {0, 1, 2, 3, 4, 5};
int *p;
p = a[0];
printf ("%d\n", p[0]);

printf ("sizeof (a) = %d, sizeof (a[1]) = %d, sizeof (a[2][1]) = %d\n", sizeof (a), sizeof (a[1]), sizeof (a[2][1]));
return 0;
}


输出结果:

0

sizeof (a) = 24, sizeof (a[1]) = 8, sizeof (a[2][1]) = 4

B:二级指针

#include <stdio.h>

int main(void)
{
char *p = "abcdef";
char **p1 = &p;
system("pause");
return 0;
}


二级指针即存放地址的指针。

(3)函数指针

显而易见,函数指针为指向函数的指针。

分析下面的函数指针:

char * (fun)(char p1,char * p2);

fun首先与 ‘*’结合所以呢他是一个指针,去掉(*fun)

char * (char * p1,char * p2);

可见fun这个指针变量指向了一个函数,这个函数的参数 (char * p1,char * p2);返回类型为 char*。

相当于char * ()(char p1,char * p2) fun1;

char *my_strcpy(char *dest, const char *src)
{
char *tmp = dest;

while ((*dest++ = *src++) != '\0')
/* nothing */;
return tmp;
}

int main(void)
{
char *orig = "best";
char copy[40] = "Be the best that you can be.";
char *ps;

ps = my_strcpy(copy + 7, orig);
puts(copy);
puts(ps);
system("pause");
return 0;
}


输出结果:

Be the best

best

了解:(int)&p 这是什么?

#include <stdio.h>
void Function()
{
printf("Call Function!\n");
}
int main(void)
{
void(*p)();
*(int*)&p = (int)Function;
(*p) ();
system("pause");
return 0;
}


输出结果

Call Function!

void (*p)();

这行代码定义了一个指针变量 p, p 指向一个函数,这个函数的参数和返回值都是 void。

&p 是求指针变量 p 本身的地址。

(int*)&p 表示将地址强制转换成指向 int 类型数据的指针。

(int)Function 表示将函数的入口地址强制转换成 int 类型的数据。

(int)&p=(int)Function;表示将函数的入口地址赋值给指针变量 p。

那么(*p) ();就是表示对函数的调用。

使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。

函数指针数组

#include <stdio.h>
#include <string.h>

char * fun1(char * p)
{
printf("%s\n", p);
return p;
}
char * fun2(char * p)
{
printf("%s\n", p);
return p;
}
char * fun3(char * p)
{
printf("%s\n", p);
return p;
}
int main(void)
{
char * (*pf[3])(char * p); //pf首先与[]结合表明pf为一个数组,这个数组有三个元素,去掉pf[]    char * (*)(char * p);可以看出每个元素是一个函数指针,这个函数参数为 char* 返回类型为 char*

pf[0] = fun1;
pf[1] = &fun2; // 可以用函数名加上取地址符
pf[2] = fun3;

pf[0]("fun1");
pf[0]("fun2");
pf[0]("fun3");
system("pause");
return 0;
}


输出结果

fun1

fun2

函数指针数组的指针

#include <stdio.h>
#include <string.h>
char * fun1(char * p)
{
printf("%s\n", p);
return p;
}
char * fun2(char * p)
{
printf("%s\n", p);
return p;
}
char * fun3(char * p)
{
printf("%s\n", p);
return p;
}
int main(void)
{
char * (*a[3])(char * p);
char * (*(*pf)[3])(char * p);//pf首先与'*'结合,所以他是一个指针,去掉*pf,   char * (*[3])(char * p);可以看出这个指针指向一个数组,这个数组有3个元素,去掉[3],char * (*)(char * p);
可以看出每个元素为一个函数指针,参数与返回类型都为char*

pf = &a;
a[0] = fun1;
a[1] = &fun2;
a[2] = &fun3;
pf[0][0]("fun1");
pf[0][1]("fun2");
pf[0][2]("fun3");
system("pause");
return 0;
}


输出结果

fun1

fun2

fun3

以上就是我对数组指针,指针数组,函数指针的一些简单认识,有不足之处希望大家指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐