九、指针

指针
Byte字节作为内存最小单元
int占用4个字节
1.内存地址和指针
变量存放在内存当中 ------>找到变量在内存当中的位置 就可以操作这个变量
数组元素的首地址--->地址

在形参中传参主要的是传递的地址

指针存放地址的类型 指针通过地址 去访问 去修改变量的值

1.函数传参 2.使用堆内存
2.指针定义和使用方式
指针就是地址
指针变量用来存放地址

 1 int *q = (int *)malloc(sizeof(int)* 100);//申请堆内存 第一个(int*)是强转 第二个(int)是申请int大小的空间
 2     
 3     if (q == NULL)
 4     {
 5         printf("申请失败");
 6         getchar();
 7         return 0;
 8     }
 9     //q指向了这块空间的首地址
10     *q = 12;//===q[0]
11     *(q + 1) = 13;//===q[1]
12     q[2] = 14;//===(*q+2)
13     q[3] = 15;
14     for (size_t i = 0; i < 4; i++)
15     {
16         printf("%d
", q[i]);
17     }
18     q = (int*)realloc(q, sizeof(int)* 200);//把之前的100个int扩充到200个int
19     printf("重新分配后
");
20     for (size_t i = 0; i < 4; i++)
21     {
22         printf("%d
", q[i]);
23     }
24     printf("q的值%p
", q);
25     free(q);//释放内存

int类型 double类型


如果只有一个地址 没法判断这个地方是什么类型的数据

指正是有类型的!!!

一个地址里面存放是int类型的值 int* 表示存放int类型的地址
一个地址存放的时候double类型的值

一级指针 地址存放基本数据类型

int float double char
%p输出地址
* 运算符 解引用

如果变量x的地址 存放在指针p 里面 p指向这个变量

int*类型的指针 指向int类型的变量

int y;
int*p;//定义一个指向int类型变量的指针
p=&y;//将y的地址 赋值给指针p
*p=2;//将y存放的内容赋值2 y就为2
printf("%p=%d",&y,y); &y输出y存放的地址


形参不能改变实参
需要在其他函数中 修改实参的值 通过传递地址的方式修改


类型* 指针变量名

int* p;//int* 表示指针类型 p表示变量名
一维数组 也可以用一级指针

数组名 vs 指针

数组名 表示数组的首地址 数组名不可以修改(视为常亮)
指针可以修改

sizeof求大小 数组名 得到的数组的大小
如果得到指针大小

1 void fun(int arr[][5])//形参实际上是指针   int*arr  
2 {
3     int a=sizeof(arr[0]);//求的是形参的大小--->指针的大小
4     int b = sizeof(arr);
5     int c = sizeof(arr[0][0]);
6     printf("arr[0]的大小为:%d
", a);//数组定义的第一个元素的大小
7     printf("arr的大小为:%d
", b);//数组指针arr的大小 为4
8     printf("arr[0][0]的大小为:%d
", c);
9 }

int arr[10]

错误用法 arr++
数组名[下标]

数组名和指针 都可以用* []


指针 申请堆内存

程序运行的时候 代码数据 加载内存当中

内存四区
代码区 存放代码二进制
全局静态常量区(全局静态 常量区)
全局函数外定义的变量 作用域是整个程序
静态 static 修饰变量 用static修饰的变量存放在全局静态区

1 void fun2()//全局静态常量区
2 {
3     static int x = 0;//静态变量x 每次调用的时候运算结束 值都会改变
4     ++x;
5     printf("x=%d
", x);
6 }

常量区 存放一些数字常量或者字符常量

没法取到地址


栈区 局部变量(函数 循环里面定义变量) 形参
都会存放在栈区
栈区 小的空间 内存操作系统控制
4M
堆区 1G 需要申请释放 需要用到函数专门申请内存
申请内存需要用到指针

申请内存 malloc 用于申请内存
释放内存 free

realloc 内存重分配 在原有内存的基础上 加/减 内存

传参

int 有int*  一级指针  保留int的地址

int*p ---> p也是变量 p也有地址 如果得到p的地址 定义二级指针来接受p的地址
int** pp=&p; 二级指针

*pp --->得到的是pp指向的内容 也就是p

printf("%d ",x)

一维数组 传参 用一级指针
二维数组 传参 数组指针

int dArr[3][4]---->int (*pd)[4] 数组指针

 1 void fun3(int(*pd)[4])//指针数组相当于int dArr[][4]
 2 {
 3     for (size_t i = 0; i < 12; i++)
 4     {
 5         printf("%d	",(*pd)[i]);//二维数组传入参数 利用指针可以用一级指针的方式进行保存
 6     }
 7     printf("
");
 8     for (size_t i = 0; i < 3; i++)
 9     {
10         for (size_t j = 0; j < 4; j++)
11         {
12             printf("%d	",pd[i][j]);//二维数组进行二维数组下标的方式进行输出
13         }
14     }
15 }
 1 void test()//数组指针vs指针数组
 2 {
 3     int(*pd)[10];//指针数组  数组的行号不定 列号为10 相当于pd[][10]
 4     int* dArr[10];//数组指针需要申请堆内存
 5     for (size_t i = 0; i < 10; i++)
 6     {
 7         dArr[i] = (int*)malloc(sizeof(int)* 4);//申请四个内存的空间 10行4列 相当于dArr[10][4]
 8     }
 9     for (size_t i = 0; i < 10; i++)
10     {
11         for (size_t j = 0; j < 4; j++)
12         {
13             dArr[i][j] = j;
14             printf("%d	", dArr[i][j]);
15             if (j == 3)
16                 printf("
");
17         }
18     }
19 
20     for (size_t i = 0; i < 10; i++)//一个一个释放内存
21     {
22         free(dArr[i]);
23     }
24 }

[] 解引用
p[i]===*(p+i)


基本数据 int x --->实参 写整数或者整形变量
变量地址 修改变量的值 int*px 实参 变量地址
数组名 操作一维数组 int *px /int arr[] 实参一维数组的数组名


const 常属性 不可变 定义的还是变量
通过语法限定 x的值不可以修改 必须先定义后赋值
常量指针
const int* p;//int const *p const限定了p不能修改他指向的内容
指针常量
int* const q;

 1 void test1()//const的妙用
 2 {
 3     int arr[10] = {0,1,2,3,4,5,6,7,8,9};
 4     const int* p;//const限定了这个p不能修改他指定的内容 即*p=0是错误的 
 5     p = &arr[0];//但是可以修改指针指向的地址  让p指向第一个元素
 6     p++;//也可以进行后移一位进行指向下一个地址
 7     //const在前*在后 是代表的常量指针
 8     printf("p的地址是:%p
", p);
 9     printf("p的值是:%d
",*p);//此时的p相当于p[1]===arr[1]
10     
11     
12     //const在*后面   指针常量
13     int* const q = &arr[0];//const 后面的q q在定义之后不能赋值
14     //q = &arr[0];//q的值不可修改 只能修改*q的值
15     *q = 0;//指针q可以去修改指向的内容
16     //使用指针传参 提高了效率 修改形参值
17 
18 }

指针传参 提高效率 修改形参的值

函数指针 返回值为指针的函数 malloc作用申请内存 返回值是一个指针
函数指针 指向函数的指针
函数调用的过程 函数名--->函数 传递形参 计算 得到返回值 回到主函数

1 void *(*pfun)(size_t _Size);
2 pfun=malloc;
3 //pfun指向函数的地址---->利用pfun来调用这个函数
4 int *p=(int*)pfun(100*sizeof(int));

指针地址效果简介

 1 #include<stdio.h>
 2 int main()
 3 {
 4     int x=3;
 5     int* p=&x;
 6     int y=5;
 7     *p=y;
 8     printf("p的值:%d
",*p);
 9     printf("p的地址:%d
",p);
10     printf("x的地址:%d
",&x);
11     printf("x的值:%d
",x);
12     printf("y的地址:%d
",&y);
13     printf("y的值:%d
",y);
14     getchar();
15     return 0;
16 }

指针效果整体代码

#include<stdio.h>
#include<stdlib.h>//malloc
void fun(int arr[][5])//形参实际上是指针   int*arr  
{
    int a=sizeof(arr[0]);//求的是形参的大小--->指针的大小
    int b = sizeof(arr);
    int c = sizeof(arr[0][0]);
    printf("arr[0]的大小为:%d
", a);//数组定义的第一个元素的大小
    printf("arr的大小为:%d
", b);//数组指针arr的大小 为4
    printf("arr[0][0]的大小为:%d
", c);
}
void fun2()//全局静态常量区
{
    static int x = 0;//静态变量x 每次调用的时候运算结束 值都会改变
    ++x;
    printf("x=%d
", x);
}
void fun3(int(*pd)[4])//指针数组相当于int dArr[][4]
{
    for (size_t i = 0; i < 12; i++)
    {
        printf("%d	",(*pd)[i]);//二维数组传入参数 利用指针可以用一级指针的方式进行保存
    }
    printf("
");
    for (size_t i = 0; i < 3; i++)
    {
        for (size_t j = 0; j < 4; j++)
        {
            printf("%d	",pd[i][j]);//二维数组进行二维数组下标的方式进行输出
        }
    }
}

void test()//数组指针vs指针数组
{
    int(*pd)[10];//指针数组  数组的行号不定 列号为10 相当于pd[][10]
    int* dArr[10];//数组指针需要申请堆内存
    for (size_t i = 0; i < 10; i++)
    {
        dArr[i] = (int*)malloc(sizeof(int)* 4);//申请四个内存的空间 10行4列 相当于dArr[10][4]
    }
    for (size_t i = 0; i < 10; i++)
    {
        for (size_t j = 0; j < 4; j++)
        {
            dArr[i][j] = j;
            printf("%d	", dArr[i][j]);
            if (j == 3)
                printf("
");
        }
    }

    for (size_t i = 0; i < 10; i++)//一个一个释放内存
    {
        free(dArr[i]);
    }
}
void test1()//const的妙用
{
    int arr[10] = {0,1,2,3,4,5,6,7,8,9};
    const int* p;//const限定了这个p不能修改他指定的内容 即*p=0是错误的 
    p = &arr[0];//但是可以修改指针指向的地址  让p指向第一个元素
    p++;//也可以进行后移一位进行指向下一个地址
    //const在前*在后 是代表的常量指针
    printf("p的地址是:%p
", p);
    printf("p的值是:%d
",*p);//此时的p相当于p[1]===arr[1]
    
    
    //const在*后面   指针常量
    int* const q = &arr[0];//const 后面的q q在定义之后不能赋值
    //q = &arr[0];//q的值不可修改 只能修改*q的值
    *q = 0;//指针q可以去修改指向的内容
    //使用指针传参 提高了效率 修改形参值

}
void test2()
{
    void *(*pfun)(size_t _Size);
    pfun = malloc;
    //pfun指向函数的地址---->利用pfun来调用这个函数
    int *p = (int*)pfun(100 * sizeof(int));
}

int main()
{
    int arr[4][5];
    fun(arr);
    fun2();
    fun2();
    fun2();
    int dArr[3][4] = {1,2,3,4,5,6,7,8,10,9,11,12};
    fun3(dArr);
    printf("
");
    int *q = (int *)malloc(sizeof(int)* 100);//申请堆内存 第一个(int*)是强转 第二个(int)是申请int大小的空间
    
    if (q == NULL)
    {
        printf("申请失败");
        getchar();
        return 0;
    }
    //q指向了这块空间的首地址
    *q = 12;//===q[0]
    *(q + 1) = 13;//===q[1]
    q[2] = 14;//===(*q+2)
    q[3] = 15;
    for (size_t i = 0; i < 4; i++)
    {
        printf("%d
", q[i]);
    }
    q = (int*)realloc(q, sizeof(int)* 200);//把之前的100个int扩充到200个int
    printf("重新分配后
");
    for (size_t i = 0; i < 4; i++)
    {
        printf("%d
", q[i]);
    }
    printf("q的值%p
", q);
    free(q);//释放内存
    printf("q的值%p
", q);
    //内存释放后  q指向的空间就不要访问
    //q依然指向这个空间 释放之后再用就会出现问题

    int x=2;
    int *p = &x;//一级指针存放x的地址
    int **pp = &p;

    printf("x=%d
",x);
    printf("p=%d
", p);//x的地址====&x
    printf("pp=%d
", pp);//p的地址===&p

    printf("x的地址%d
", &x);
    printf("p的地址%d
", &p);

    printf("%d
", *pp);//x存放的地址===&x
    printf("%d
", **pp);//x的值===x
    printf("%d
", *p);//x的值===x

    test();
    test1(); 
    test2();
    getchar();
    getchar();

    return 0;
}

原文地址:https://www.cnblogs.com/liugangjiayou/p/11771808.html