0
点赞
收藏
分享

微信扫一扫

C语言学习记录——이십팔 指针详解(1)

Android开发指南 2022-04-13 阅读 57

先回顾一下之前学的指针:

1、指针是个变量,用来存放地址,地址唯一标识一块内存空间。

2、指针的大小是固定的4/8个字节(32/64位平台)

3、指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。

4、指针的运算

字符指针

类型是char*

int main()

{

char arr[] = "abcdefg";

char* pc = arr;

printf("%s\n", arr);

printf("%s\n", pc);

return 0;

}

pc接受arr数组首元素地址,输出时从这个地址开始往后输出。同样的,除了字符数组,字符串也一样。

int main()

{

char* p = "abcdefg";  //这是一个常量字符串

printf("%s\n", p);

return 0;

}

p接受的是a的地址,然后从a开始输出。而关于这个字符串在内存中的布局需要再写一写。

字符串abcdefg\0,存入内存后会有一个起始地址,这个地址被指针变量p存放,p就可以通过这个指针指向a,然后打印整个字符串。

如果在代码里加入*p = 'M',再打印,会出现错误,不会打印Mbcdefg。abcdefg是个常量字符串,不能更改,强行更改代码会崩溃,会出现段错误segmentation fault,访问内存错误等等。为了防止这样的错误,可在char*前加上const,这样*p就不能被更改了。

看一道题

int main()

{

    char arr1[] = "abcdef";

    char arr2[] = "acbdef";

    char* p1 = "abcdef";

    char* p2 = "abcdef";

    if (arr1 == arr2)

    {

        printf("hehe\n");

    }

    else

    {

        printf("haha\n");

    }

    return 0;

}

arr1数组名代表的首元素地址和arr2所代表的不同,所以不一样,打印haha。这里改一下。

把 if (arr1 == arr2)改成if (p1 == p2)

    char* p1 = "abcdef";

    char* p2 = "abcdef";

字符串一样,是常量字符串,内存中存放的时候没有给p1和p2两个地址,节省空间,p1和p2指向同一个地址,这个地址也就是abcdef的地址,改变p1不影响p2。所以应该在char前加上const,进一步防止字符串被改变

指针数组

是用来存放指针的数组。可以有不同类型,int*, short*等等。比如char* arr[5]。举一个例子

int main()

{

    int a = 10;

    int b = 20;

    int c = 30;

    int d = 40;

    int* arr[4] = {&a, &b, &c, &d};

    return 0;

}

查看内存,arr里的四个地址和abcd一样。如果要打印abcd的值,不能用这样的方法

int i = 0;

for(i = 0; i < 4; i++)

{

    printf("%d", *(arr[i]));

}

可以打出来值,但是指针数组没有这样的用法

int main()

{

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

    int arr2[] = {2, 3, 4, 5, 6};

    int arr3[] = {3, 4, 5, 6, 7};

    int* parr[] = {arr1, arr2, arr3};

    return 0;

}

看看这个用法,分析一下。     三个数组arr1,arr2,arr3,分别存放着内容,parr这个数组,里面的元素类型都是int*,现在存入arr1这个数组名,也就是首元素地址,指向各个数组的首元素地址,这也是一个整形数组。接下来打印所有数字

int main()

{

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

    int arr2[] = {2, 3, 4, 5, 6};

    int arr3[] = {3, 4, 5, 6, 7};

    int* parr[] = {arr1, arr2, arr3};

    int i  = 0;

    for(i = 0; i < 3; i++)

    {

        int j = 0;

        for(j = 0; j < 5; j++)

        {

            printf("%d ", *(parr[i] + j));

        }

        printf("\n");

    }

    return 0;

}

这样使用指针数组就可以正确打印出数据。

指针数组有一级,二级等,也就是char*, char**.

数组指针

数组指针是指针。能够指向数组的指针。数组类型的指针,可存放数组的地址

int main()

{

    int arr[3] = {1, 2, 3};

    int (*p)[3] = &arr;

    return 0;

}

如果写成int *p[3],那么整体就是一个数组,而非指针。因为p和[]结合形高于和*,所以p先和[3]结合,形成一个数组,再变成一个指针类型。应当用int (*p)[3] = &arr,使p变为一个指针类型,然后指向一个数组,数组元素个数为3,里面存放着arr,这也就是个数组指针,指针类型就是char*。不过很少这样写:int (*p)[3] = &arr。

&arr,是数组的地址,而不是首元素地址,单纯的一个arr数组名是首元素地址。

基本用法

int main()

{

    int arr[3] = {1, 2, 3};

    int (*pa)[3] = &arr;

    int i = 0;

    for(i = 0; i < 3; i++)

    {

        printf("%d\n", *(*pa + i));

        printf("%d\n", (*pa)[i]);

    }

    return 0;

}

pa存放着arr这个数组地址,解引用其实*pa == arr。上面两种方法都可,但是不正确。

int main()

{

    int arr[3] = {1, 2, 3};

    int *pa = arr;

    int i = 0;

    for(i = 0; i < 3; i++)

    {

        printf("%d\n", *(pa + i));

    }

    return 0;

}

直接让pa存放arr这个数组即可。

数组指针的用法并不是上面那两种用法,显得繁琐。数组指针用于二维数组以上才方便。

void print1(int arr[3][5], int x, int y)

{

    int i = 0;

    int j = 0;

    for(i = 0; i < x; i++)

    {

        for(j = 0; j < y; j++)

        {

            printf("%d\n", arr[i][j]);

        }

        printf("\n");

    }

}

int main()

{

    int arr[3][5] = {{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}};

    print1(arr, 3, 5);

    return 0;

}

这是一个很简单的程序,运用数组指针的话

void print2(int (*p)[5], int x, int y)

{

    int i = 0;

    for(i = 0; i < x; i++)

    {

        for(j = 0; j < y; j++)

        {

            printf("%d\n", *(*(p + i) + j));

        }

        printf("\n");

    }

}

int main()

{

    int arr[3][5] = {{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}};

    print2(arr, 3, 5);

    return 0;

}

数组名是首元素地址,一维数组就是第一个元素地址,而二维数组,可以看做每一行就是一个一维数组,就是一个元素,数组名就是第一行的地址。传参过去后,由于传的是一维数组,接收数组需要用到数组指针,所以int (*p)[5]。*(*(p + i) + j),p代表着一行的元素,p+i意味着跳过i行,比如i = 1,就来到了第二行,每行具体的元素,需要加上j,也可以(*(p + i))[j],也能访问到具体数字。

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

int i = 0;

int* p = arr;

for(i = 0; i < 5; i++)

{

    printf("%d", p[i]);

    printf("%d", *(p + i));

    printf("%d", *(arr + i));

    printf("%d", arr[i]);

    return 0;

}

这四个都可以打印出arr数组里所有的元素。arr被赋值给p后,arr就相当于p,这四个*(p + i) == p[i]。依据这个,看之前的二维数组代码,也就可看出:

p[i][j] == *(p[i] + j) == *(*(p + i) + j) == (*(p + i)[j])

当看完这些后,再加深一下印象

int arr[5]     是一个5个元素的整形数组

int *parr1[10]      parr1是一个有10个元素的数组,元素类型是int*,这是一个指针数组

int (*parr2)[10]    parr2是一个指针,指向一个有十个int类型元素的数组,这是一个数组指针

int (*parr3[10])[5]     该数组有10个元素,每个元素是一个数组指针,该数组指针指向的数组有5个,每个元素是int。

结束。

举报

相关推荐

0 条评论