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

来源:互联网 发布:计算微积分的软件 编辑:程序博客网 时间:2024/04/30 06:47

数组指针:首先呢他是一个指针,他有能力指向一个数组。
指针:其数值为地址的变量。

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];p首先与 结合,所以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][N] = { 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

以上就是我对数组指针,指针数组,函数指针的一些简单认识,有不足之处希望大家指出。

阅读全文
0 0
原创粉丝点击