c语言指针与数组

int *a;//指向int 变量

int **a;//等价于int *a[],指向一个地址,改地址存放值是一个指向int 变量的指针

int (*p)[3];//等价于二维数组int p[][3],第一维度每加1,地址加第二维度个长度(这里是sizeof(int)*3)

int**a

int **a与int (*a)[3]区别:

他们都可以像a[0][0]这样使用,但是其实有很大区别。对于int **a,二维数组形式可以用并不表示他是二维数组,因为[]只是扩展为*(*(a+0)+0)这样的形式。可以用只是因为符合这种用法。举例:

int **a={"fdasfsa","fdsaf","34243"};

如果a是二维数组,那么他们在第二维度的长度是一样的并且a[0]的最后一个元素和a[1]的第0个元素相邻。但是这里只不过有三个任意地址的任意长度字符串,"fdasfsa","fdsaf","34243",他们长度不需要相同,地址不需要相邻。仅仅是因为有三个指针分别指向了"fdasfsa","fdsaf","34243",刚好这三个指针在a[]这个数组里面。现在理解a[0][0]的写法,就是通过a[0]得到了"fdasfsa"地址,然后后面的操作就和普通一维数组一样了。a[0][0]就是第0个元素,a[0][1]是第二个以此类推。需要注意的是,a[0]与a[1]在地址上是连续的,因为他们是a数组里面的元素。

#include "stdio.h"


#define STR4    "4str401321"
#define STR3    "3str37894"
#define STR2    "2str24567"
#define STR1    "1str10123"

int fun()
{
    printf("hello world\r\n");
    return 0;
}
int main()
{
    int t[10] = {0,1,4,7,8,9,10,3,2,3};
    int *tp = t;
    int a[3][3] = {0,1,2,3,4,5,6,7,8};
    int (*b)[3] = a;
    char *pc1 = STR4;
    char *pc2 = STR3;
    char *c[]= {STR1,STR2,STR4};
    char **cc = c;

    printf("%X %X %X\n",c,c+1,c+2);
    printf("%X %X %X\n",c[0],c[1],c[2]);
    
}

结果:

61FD80 61FD88 61FD90
404022 40402C 40400D
8

 可以c看到这里是连续的(64位程序,指针8字节),但是里面字符串地址有连续的STR1与STR2,有反过来的STR4与STR1,这涉及到创建对应字符串时的内存分配。

int (*a)[]

int(*a)[]等于a[][]二维数组,带赋值的时候即可发现,如int **a = a[][];会提醒(*)[]不能赋值给**。其定义中*a表示a是指针,[]表示指针对象是数组,但是数组有大小,所以需要提供[3]形式的定义。

穿插一个关于指针偏移操作的内容。现在编译器不分长指针,短指针,长度统一,那为什么还会区别char int指针呢?虽然指向对象不一样,但是int指针与char指针指的都是一个地址,通过强制转换可以随意指。我的理解是涉及其访问的偏移。对于int *a;a=(int*)0X0;a+1就得到0X08;而char *a = (char*)0X0;a+1得到0X01;对于结构体,同理。对于int *a,等价于a[],在a+1的结果上也相同,这点可以理解,&a结果也相同。但是二者对于sizeof(a)与&a+1结果就不同。对于*a其加1时候偏移一个int*的长度,而对于a[] a+1时偏移了[]中数字大小*sizeof(int)的长度,也就是数组长度。

 继续回到关于(*a)[]的分析。当访问a[1][0]时候会转换为*(*(a+1)+0),此时a+1的偏移并不是指针的8字节,而是一个第二维度数组的长度。所以可以通过a[][]的形式遍历一个二维数组。

int main()
{
   

    int t[10] = {0,1,4,7,8,9,10,3,2,3};
    int *tp = t;
    int a[3][3] = {0,1,2,3,4,5,6,7,8};
    int (*b)[3] = a;
    char *pc1 = STR4;
    char *pc2 = STR3;
    char *c[]= {STR1,STR2,STR4};
    char **cc = c;

    int atv[2][2][2] = {0};
    for(int i = 0;i < 3;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            printf("%d ",a[i][j]);
        }
        printf("\n");
    }

    for(int i = 0;i < 3;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            printf("%d ",*(*(a+i)+j));
        }
        printf("\n");
    }

    printf("t+1 =%X\ttp+1= %X\n",t+1,tp+1);
    printf("&t+1 =%X\t&tp+1= %X\n",&t+1,&tp+1);
    printf("sizeof(t) = 0X%X\tsizeof(tp) = 0X%02X\n",sizeof(t),sizeof(tp));
}

结果:

0 1 2
3 4 5
6 7 8
0 1 2
3 4 5
6 7 8
t+1 =61FDC4     tp+1= 61FDC4
&t+1 =61FDE8    &tp+1= 61FDC0
sizeof(t) = 0X28        sizeof(tp) = 0X08

三维四维等同理int (*p)[3][3]的形式。

int(**p)()

首先函数指针是int(*p)()的形式,不难理解int *(*p)()是返回int指针的函数指针,int(**p)()就不言而喻了,是指向指针的指针。用法:

int fun(){}

int (*p)() = fun;

int (**pp)() = &p;

这样就可以通过p()和(*pp)()调用fun了。

不能通过pp=&fun赋值。因为fun和&fun值一样,与数组类似。

而函数指针数组就是形为int(*p[3])()定义的数组。

可以通过如下形式使用:

    int fun()
{
    printf("hello world\r\n");
    return 0;
}
int main()
{

    int (*p_a[3])();
    int(*p)() = &fun;
    int(**pp)() = &p;
    (*pp)();
    pp = p_a;
    pp[0] = p;
    pp[0]();
}

你可能感兴趣的:(c语言,算法,数据结构)