pointer_to_the_advanced(指针进阶)——重置版

Posted Dark And Grey

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pointer_to_the_advanced(指针进阶)——重置版相关的知识,希望对你有一定的参考价值。

文章目录

回顾指针

1,指针就是个变量,用来存放地址,地址 唯一标识 一块 内存空间。
2.指针的大小是固定的 4 / 8字节(32位平台 / 64位平台)。
3.指针是有类型的 ,指针的类型决定了指针的 +- 整数的步长,指针解引用操作的时候的权限(一次访问几个字节内容)
4.指针的运算

举个例子回忆一下

#include<stdio.h>
void test(int* arr)// 这里的 arr 是 数组首元素地址的一份拷贝
{
    printf("%d\\n",sizeof(arr[0]));// 计算的数组的一个元素大小,输出为 4
     printf("%d\\n",sizeof(arr));// 计算的是地址的大小(这里不能算是数组的地址,因为 该地址是test传过来的  首元素地址  的一份拷贝),输出为 4
//  32位系统     
     sizeof(arr)在这里是求指针(地址)大小(4 byte)    
     sizeof(arr[0])在这里求的是一个元素的大小,int类型(4字节)
      如果是64位系统。指针大小为 8 字节,输出此时就为 2
}

int  main()
{
    int arr[10] = { 0 };
    test(arr);//传过去的是数组首元素地址,因为不是单独 与 sizeof 和 & 操作符连用
    return 0;
}

1.字符指针

在指针的类型 中 我们知道有一种 指针类型 为 字符指针 char*·

程序一:

#include<stdio.h>
int main()
{
    char ch = 'w';
    char* pc = &ch;
    *pc =='w';
    return 0;
}

程序二:

#include<stdio.h>
int main()
{
    char arr[] = "abcdef";
    char* pc = arr;//这里存入的是首元素 a 的地址
    printf("%s\\n",arr);//abcdef
    printf("%s\\n",pc);//abcdef   两者都是向后打印,直到遇到'\\0'停止
    %s 就是 根据 给的地址位置开始向后打印的,知道遇到'\\0'停止
    return 0;
}

程序三:

#include<stdio.h>
int main()
{ 
    char* p = "abcdef";// "abcdef" 双引号引起来的abcdef\\0,是一个常量字符串
    // 上表达式的意思是,把 a 的地址 存入指针变量p里面去
    printf("%c\\n",*p);// *p == a
    // 输出为 a
    printf("%s\\n",p);//从存入p的这个地址(首元素a的地址)开始往后打印知道遇到 '\\0'
    // 即输出为 abcdef
    return 0;
}

程序四:

#include<stdio.h>
int main()
{
    const char* p = "abcdef";// 最稳妥写法,就是在 * 前面加上 const
    *p = 'w';// 这时候你想改都改不了,况且 "abcdef" 是一个常量字符串,也改不了
    printf("%s\\n", p); //你会发现 没有任何输出,程序崩溃。违规操作
    //还有一个原因 abcdef\\0 是一个常量字符串,是不可以被改变的(const:是变量具有常量属性)
    return 0;
}

程序五:

#include<stdio.h>
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abcdef";                     
    if (arr1 == arr2)//这里是两个不同数组的数组名(不同的首元素地址),是否相同
         //肯定不同,两个不同数组的起始空间肯定不一样
    {
        printf("hehe\\n");
    }
    else
    {
        printf("haha\\n");// 所以输出这条语句
    }
    return 0;
}

程序六:

#include<stdio.h>
int main()
{


    建议下面两句表达式在 * 前面防疫 const  ,这样就更保险,无法通过解引用去修改常量字符串的内容
     这样写,虽然意义不大(常量字符串本身并不能被修改),语法更为准确
    const char* p1 = "abcdef";
    const char* p2 = "abcdef";
    这里把常量字符串 abcdef\\0 的首元素(a)地址分别存入 2 个指针变量
    是因为abcdef\\0是常量字符串,不可改变,因此没有必要创建2个,直接共用一个,即 p1 == p2
    if (p1 == p2)
    {
        printf("hehe\\n");// 所以输出这条语句
    }
    else
    {
        printf("haha\\n");
    }
    return 0;
}

指针数组 - 本质上是一个数组

pointer文章中,我们也学了指针数组,指针数组 指的是一个 存放指针 的数组

程序一:

#include<stdio.h>
int main()
{
    int arr[10] = { 0 };// 整形数组
    char ch[5] = { 0 };// 字符数组
    int* parr[4];// 这就是一个存放 整形指针 的数组,简称 指针数组 
    char* pch[5];// 这就是一个存放 字符指针 的数组,简称 指针数组 
    return 0;
}

程序二:

#include<stdio.h>
int main()
{

    int a = 10;
    int b = 20;
    int c = 30;
    int d = 40;
                                  
    int* arr[4] = { &a, &b, &c, &d }; 
    等价于     //int* pa = &a;
              //int* pb = &b;
              //int* pc = &c;
              //int* pd = &d;
    int i = 0;
    for (i = 0; i < 4; i++)
    {
        printf("%d ",*arr[i]);// 10 20 30 40
    }
    return 0;   // 指针数组很少怎么用 ,下面程序将告诉你,指针数组怎么使用
}

程序三:

#include<stdio.h>
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++)// 遍历 指针数组 parr 的元素
    {
        int j = 0;
        for (j = 0; j < 5; j++)// 遍历 指针数组 parr 的 元素 所指向的 数组 的 元素
        {
            printf("%d ",*(parr[i] + j));
        }
        printf("\\n");
    }
    return 0;  
}

这里我们回顾一下 二级指针

int* arr1[]; //一级整形指针数组.
int** arr[];// 二级整形指针数组
ichar* arr2[]; //一级字符指针数组
char** arr2[]; //二级字符指针数组


数组指针 - 指针

程序一:

#include<stdio.h>
int main()
{
    int* p = NULL;// 整形指针 - 指向 整形 的指针   作用:可以 存放  整形的地址
    char* pc = NULL;//字符指针 - 指向 字符 的指针  作用:可以 存放  字符的地址 


数组指针 - 指向 数组 的指针   作用:可以 存放  数组的地址
    //int arr[10] = { 0 };  整形数组
    // arr - 首元素地址
    // &arr[0] - 首元素的地址 
    // &arr - 数组的地址

    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int(* p)[10] = &arr;// 把数组的地址存起来
    // 为什么不能去掉(),因为 [] 的优先级 比 * 高,去掉(),p就和数组[10]先结合,就成 指针数组(存放指针的数组) 了
    // 加 () 把 * 和 p 先结合,使 p 成为一个指针 (另外请注意 这里不是解引用,只是说明 p 是一个指针)
    // 把 *p 去掉,还剩int [10],意思就是说该指针(p)指向 一个 元素个数为 10 的数组,且数组每个元素的类型为整形
    // 即 上表达式 int(*p)[10] 就是数组指针
    return 0;
}

程序二:

#include<stdio.h>
int main()
{
    char* arr[5];
    //如何把上表达式的数组存入 数组指针?
    如下
    char*(*pa)[5]=&arr;
    // 先用()把 * 和 pa(指针变量名) 结合起来,使 pa 为一个指针,也就是说 * 告诉我们 pa 是个指针
    //再在后面加[5],意思是 指针 指向一个元素个数为5的数组
    // 又因为 指针 指向的数组 的  元素类型 为 char*,所以在前面补上

    int arr2[10] = { 0 };
    int (*pa2)[10] = &arr2;
    return 0;
}


&数组名 VS 数组名

数组名 绝大部分时候 都是为 首元素地址

只有两种情况例外  &数组名  和  sizeof(数组名)
在这两种情况下的数组名,代表是整个数组,取出的是数组的地址(与数组首元素地址相同,但意义不同)

举个例子

&arr+1 - 直接 跳过一整个 数组的字节
比如 int arr[10],他的大小是40个字节,&arr+1 数组地址会加上40
如果是 arr+1 它就只跳过一个元素,意思就是 跳过第一个元素,地址指向第二个元素


数组指针的用法 : 一般用在 二维数组

程序一:

#include<stdio.h>
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10};
    int (*pa)[10] = &arr;
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        //printf("%d ",(*pa)[i]);// *pa 就相当于数组名  *pa  ==  arr
        printf("%d ",* (*pa+i) );//等价于 printf("%d ",*(arr+i))
    }
    return 0; // 但 数组指针 不是这么用的,以上只是让你对它理解更深一点
}

在 明白 数组指针 的真正用途之前,我们需要观察一个程序

#include<stdio.h>
int main()
{
    int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int i = 0;
    int* p = arr;// 指针变量p 接收的是 数组的首元素地址,即 p == arr
    for (i = 0; i < 10;i++)
    {
        printf("%d ",*(p+i));// 通过数组首元素的地址,来遍历数组元素
    }
    printf("\\n");
  上下两个循环表达大额效果是相同的
    for (i = 0; i < 10; i++)
    {
        printf("%d ", *(arr + i));
    }
    printf("\\n");



    for (i = 0; i < 10; i++)
    {
        printf("%d ", arr[i]);// arr[i] == *(arr+i) == *(p+i) == p[i]
    }
    printf("\\n");
  上下两个循环表达大额效果是相同的
    for (i = 0; i < 10; i++)
    {
        printf("%d ", p[i]);// arr[i] == p[i]
    }

    //以上所有写法都是等价的。
    return 0;
}

程序二(数组指针的用法):

#include<stdio.h>
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 ",arr[i][j]);// printf("%d ". *(*(arr+i)+j) );
        }
        printf("\\n");
    }
}

void print2(int(*p)[5], int x, int y)//由于 二维数组转过的是 首元素地址(一维数组的地址),需要一个一维数组指针来接收
{
    int i = 0;
    int j = 0;
    for (i = 0; i < x; i++)// t通过双重循环,来遍历二维数组
    {
        
        for (j = 0; j < y; j++)
        {
            //printf("%d ", *(*(p+i)+j));// p 是 一维数组的地址 (一行),*p 就是找到了第一行的数据,也就是一维数组的数组名  
                                       // *( p + i),i=0,还是第一行,i=1 是第二行, i=2 第三行
                                       // *(p+i)+j  就是第几行 第几个元素
            printf("%d ",p[i][j]);
// *(*(p+i)+j)== p[i][j] 先用一个括号将 p 和 i括起来,得到一维数组的首元素地址,在对其解引用得到"数组名",
再用一个括号将其和 j 括起来,得到 i 行 第 j 个元素的地址,在对其 解引用,得到该元素的值,并将其打印(注意! []* 的优先级高)
            //printf("%d ", *(p[i]+j))     
            // *(p+i) == arr[i] == p[i]
            // *(p[i]+j) == 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} };
    print1(arr,3,5);
     这里的 数组名 就是 首元素【{12, 34, 5}】地址
     首先我们要 把二维数组 看作 一维数组,把 第一行{1,2,3,4,5}数据,也就是我们的第一个元素(首元素),看作一个一维数组 int a[5]
    //以此类推 第二行数据 就是 第二个元素(也是一个一维数组), 第三行数据 就是 第三个元素(也是一个一维数组)
    print2(arr,3,5);// 那么 传过去的是数组首元素地址,而且是一个一维数组的地址
    return 0; 
}

小汇总

int arr[10] //arr是一个整形数组,具有10个元素.

int* parr1[10];//parr1是指针数组,首先它是一个数组,具有10个元素,且每个元素的类型是(int*) ,

int(*parr2)[10];    parr2是一个整形数组指针
用括号让 * 与 parr2 先结合
所以parr2是一个指针,该指针指向了一个数组,数组有10个元素,每个元素的类型是int

int( * parr3 [10] ) [5]
因为()的优先级最高,所以先判断()里的内容
又因为 * 和[],[]的优先级更高,所以 parr3先与[]结合,所以parr3是个数组
把 parr3[10]去掉,还剩下int(* )[5] ,就是它的元素类型.

例子: int arr[10];去掉arr[10],乘下的 int,就是它的类型(整形)

那int(* )[5]是个什么类型?
仔细观察一下,你会发现,它和数组指针 int(*p)[10] 一样
.那么、我们可以说 parr3是个数组,元素有10个,每个元素都是一个整形数组指针,这个指针能指向5个元素,每个元素的类型是int.的整形数组。(我们称   int( * )[5]  为 整形数组指针类型,简称 数组指针类型 )


数组参数、指针参数

在写代码的时候难免要把 [ 数组 ] 或者 [ 指针 ]传给函数,那函数的参数该如何设计?

一维数组传参

这些是指哪些键位

GNU协议指啥?

iOS:实现单指平移和两指平移手势?

需要延迟触摸 3 指滑动而不是 1 指滑动

bw是指哪个部门

请问3D模型指的是啥东西