当前位置: 首页 > article >正文

指针学习笔记

什么是指针

省流: 指针=内存地址

在计算机科学中,指针是编程语言中的一个对象,利用地址,它直接指向存在电脑储存器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,指针指向该变量单元。因此,将地址形象化地称为指针。意思是通过它能找到以它为地址的内存单元。从另外一个方面来讲,指针就是一个变量,用来存放内存单元的地址(编码),地址唯一标识一块内存空间。

指针变量定义格式

数据类型* 变量名

int a=10;
int* p=&a;//定义一个指针区指向变量a

其中,& 是取地址运算符
ps:
1.指针变量的数据类型要跟指向变量的类型保持一致
2.指针变量占用的大小,跟数据类型无关,跟编译器有关
32位:4字节 64位:8字节
3.给指针变量赋值的时候,不能把一个数值赋值给指针变量
错误案例:

int a=10;
int* p=500;//赋值未分配空间的内存地址

指针的作用

  1. 查询数据: * 指针名

这里的 * 是解引用运算符:表示通过后面的内存地址获取相对应的数据

  1. 存储数据: * 指针名=数据值;

解引用可以修改指向的数据

*p=200;
printf("%d\n,*p);
  1. 利用指针可以修改函数外部的变量

在函数中使用指针作为参数,可以直接修改外部变量的值,而不需要通过返回值来回传。这在需要修改多个变量或者修改结构体成员时特别有用。

#include <stdio.h>
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main() {
    int x = 10, y = 20;
    printf("Before swapping: x = %d, y = %d\n", x, y);
    swap(&x, &y);
    printf("After swapping: x = %d, y = %d\n", x, y);
    return 0;
}

ps:函数中变量的生命周期跟函数相关,函数结束了,变量也会消失,此时在其他函数中,就无法通过指针使用了,如果不想函数中的变量被回收,可以在变量前面加static关键字

  1. 动态内存分配

使用指针可以在函数内部动态分配内存,并将内存地址返回给调用者。这对于处理不确定大小的数据结构非常有用。

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr = (int *)malloc(5 * sizeof(int));
    if (arr != NULL) {
        // 使用 myArray...
    }
    free(myArray); // 释放内存
    return 0;
}

指针的运算

1.指针+1或者指针-1是什么意思?
把指针中记录的内存地址,往后或者往前移动一个步长
2.步长:跟数据类型有关
windows64位操作系统
char:移动一个字节
short:移动两个字节
int:移动四个字节
long:移动四个字节
long long:移动八个字节
3.指针的运算中 有意义的操作:

  • 指针跟整数进行加、减操作(每次移动n个步长)
  • 指针跟指针进行减操作(间隔步长)
    e.g. (p2 - p1) 返回两个指针之间的元素数量

无意义的操作:

  • 指针跟整数进行乘除操作(原因:此时指针指向不明)
  • 指针跟指针进行加、乘、除操作

指向不明的指针——

  • 野指针:指针指向的空间未分配
  • 悬空指针:指针指向的空间已分配,但是被释放了

指针与数组

指向数组的制造叫做数组指针,可以方便地操作数组中的各种数据。

  1. 指针与一维数组

数组名默认是数组第一个元素的地址。
也就是说,你可以将数组名赋值给一个指针变量,此时该指针指向数组的第一个元素。
指针可以通过加法操作来访问数组的不同元素。

int *p1=arr;//arr是一个数组
for(int i=0;i<len;i++){
    printf("%d\n,*p1);
    p1++;
}
  1. 指针与二维数组

二维数组可以视为一维数组的元素也是一个数组。因此,二维数组的每一行都可以被视为一个独立的一维数组。

int a[3][5];
int (*p)[5]; // p是一个指向含有5个元素的一维数组的指针 

当我们将二维数组的名称赋给这样的指针时,实际上是指向了数组的第一行。

p = a; // p现在指向a[0],即第一行

通过指针 p 和算术运算符可以访问二维数组中的元素。

*(p + i) + j // 指向第i行第j列的元素地址
*(*(p + i) + j) // 获取第i行第j列的元素值

注意,对于指向数组的指针 p,p + 1 指向下一维数组(即下一行)。这是因为指针的步长是基于其所指向的类型决定的。对于 int (*p)[4],步长为 4 * sizeof(int)。

p + 1 // 指向第二行的首地址
  1. 数组指针与指针数组

数组指针(行指针)是专门用来指向数组的指针,它的类型反映了它所指向的数组的类型。

int (*p)[4]; // p是一个指向含有4个元素的一维数组的指针

指针数组则是一个数组,数组的每个元素都是一个指针。

int *p[3]; // p是一个由3个整型指针组成的数组

指针与函数

  1. 数组名作为指针传参

当数组作为参数传递给函数时,实际上传递的是数组首元素的地址。在函数内部,可以通过这个地址来访问和修改数组的元素。

#include <stdio.h>
void printarr(int arr[], int len) {
    for (int i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}
int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int len = sizeof(arr) / sizeof(arr[0]);
    printarr(arr, len);
    return 0;
}

当需要传递多维数组时,需要注意的是,数组的第一维可以是未知大小的,但第二维必须明确指定大小。这是因为C语言中数组降维的特性,导致数组名在函数调用时会被转化为指向数组首元素的指针。

#include <stdio.h>
void printarr(int arr[][3], int len) {
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}
int main() {
    int arr[][3] = {{1, 2, 3}, {4, 5, 6}};
    int len = sizeof(arr) / sizeof(arr[0]);
    printarr(arr, len);
    return 0;
}
  1. 函数指针

格式:返回值类型 (*指针名) (形参列表)
作用:利用函数指针,可以动态地调用函数

函数指针可以作为参数传递给其他函数,这样可以在运行时决定使用哪个函数。这在实现回调函数时非常有用。

#include <stdio.h>
int dbl(int x) { return x * 2; } 
int inc(int x) { return x + 1; } 
// 接受一个整数和一个函数指针的函数
void proc(int n, int (*f)(int)) {
    int res = f(n); // 使用函数指针
    printf("%d\n", res);
}
int main() {
    int val = 5;
    proc(val, dbl); // 输出: 10
    proc(val, inc); // 输出: 6
    return 0;
}

int (*f)(int) 是一种声明函数指针的方式。在这里,f 是一个指向函数的指针,该函数接受一个 int 类型的参数,并返回一个 int 类型的值。

  • int 是函数的返回类型。
  • (*f) 表示 f 是一个指针。
  • (int) 表示函数接受一个 int 类型的参数。

二级指针

定义二级指针的方法是在类型前加上两个星号 **:

int **ptr;

初始化二级指针需要先创建一个指向 int 的指针,然后让二级指针指向这个指针:

int a = 10;
int *p1 = &a;
int **p2 = &p1;

访问通过二级指针指向的值可以通过连续使用两个星号

printf("%d\n", **ptr_to_ptr); // 输出值 10

二级指针应用场景:

  • 动态数组的管理:使用二级指针可以方便地管理和操作动态分配的数组。
  • 回调函数:在某些情况下,需要传递指向指针的指针作为参数,以便函数可以修改指针指向的对象。
  • 多维数组:在处理多维数组时,可以使用二级指针来简化操作。
#include <stdio.h>
#include <stdlib.h>

void printarr(int **arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", **arr + i); // 访问数组元素
    }
    printf("\n");
}

int main() {
    int size = 5; 
    int *arr;   // 指向数组的指针
    int **ptr_to_arr = &arr;    // 指向数组指针的二级指针

    // 动态分配内存
    arr = (int *)malloc(size * sizeof(int));
    
    // 初始化数组
    for (int i = 0; i < size; i++) {
        arr[i] = i + 1; // 填充数组元素
    }

    // 打印数组
    printarr(ptr_to_arr, size); // 输出: 1 2 3 4 5

    // 修改数组中的元素
    **ptr_to_arr = 10; // 修改数组的第一个元素
    printarr(ptr_to_arr, size); // 输出: 10 2 3 4 5
    
    free(array);// 释放内存
    return 0;
}

http://www.kler.cn/news/331765.html

相关文章:

  • 安卓使用memtester进行内存压力测试
  • Spring Boot框架:新闻推荐系统开发新趋势
  • 检索器--
  • Keepalived+MySQL 高可用集群
  • 【QT Quick】基础语法:基础类与控件
  • 汽车追尾为什么是后车的责任?
  • ip 地址查看cmd命令
  • Mysql(索引与事务)
  • 用ChatGPT做数据分析与挖掘,爽!
  • 使用transformers调用owlv2实现开放目标检测
  • 数据结构:并查集
  • Axure大屏可视化模板在不同领域中的实际应用案例
  • 基于物联网的智能环境监测系统(论文+源码)
  • Redis数据库与GO(一):安装,string,hash
  • HUAWEI WATCH GT 系列安装第三方应用
  • 【正则表达式】粗浅学习
  • Linux编辑器Vim与Nano之全面比较
  • 【60天备战2024年11月软考高级系统架构设计师——第36天:系统安全设计——数据加密】
  • C++-vector模拟实现
  • Visual Studio 小技巧记录