当前位置: 代码迷 >> 综合 >> 《C/C++学习指南》语法篇—笔记 (八、指针)
  详细解决方案

《C/C++学习指南》语法篇—笔记 (八、指针)

热度:60   发布时间:2024-02-06 01:04:38.0

《C/C++学习指南》语法篇—笔记 (八、指针)

        • 提要:变量与内存
        • 使用指针类型表示地址
        • 关于指针
        • 星号操作:按地址访问
        • 指针与数组
        • 指针作为函数的参数
        • const指针
        • 指针的安全使用

提要:变量与内存

  • 内存用于存储数据,最小单元是字节(8bit),每个单元都有一个编号(地址:0x00000000~0xFFFFFFFF),地址是一个整数
  • 变量大小(sizeof()返回变量大小),int型是4字节,变量的大小指它在内存中占了几个字节
  • 变量地址就是该变量在内存中的位置。使用&取得该变量地址。
  • 变量赋值:向内存写入数据。读变量的值,从内存中读取数据。
  • 每个变量都有自己的内存地址,绝不会有两个变量内存地址相同。
  • 程序每次运行,变量的地址是不一样的,无法预测。

使用指针类型表示地址

地址是整数,理论上可以用int,但是未来强调它是内存地址,使用 ==类型*==这个新类型来表示:

char*  :表示一个char型变量的地址
short* :表示一个short型变量的地址
int*   :表示一个int型变量的地址
float* :表示一个float型变量的地址
double* :表示一个double型变量的地址
unsigned char* :表示一个unsigned char型变量的地址

定义了一个指针类型的变量(指针),类型int*,初始值为int型变量a的地址

int a = 10;
int* ptr = &a;

关于指针

  • 指针也是变量,可以改变
  • 不同类型的指针,不能互相赋值 int* ptr1 与 double* ptr2
  • 指针即地址,地址是整数,所以指针是一个整数类型
  • 关于 * 位置 int* aint * aint *a,建议第一种。

星号操作:按地址访问

对于一个变量 int型为例,有两种方式访问,改变它的值
(1)直接使用变量名

int  = 0;
printf("a:%d",a);
a = 0x11; 

(2)使用指针(按地址访问,直接修改内存)
有一个指针变量p,*p用于访问p指向的内存(读写)

int a = 0;
int* p = &a;  //p指向a
printf("a:%d",*p);
*p = 0x11;

注意区分:指针定义语句种的 int*和 按地址访问的 *p

如果只是一个单纯int型变量,不支持按地址访问的 *操作,只有指针类型变量才可以按地址访问。虽然指针类型是int型的。

指针与数组

C/C++中,数组名就是数组的首地址,就是数组在内存中的位置。
把数组看成一块连续内存,数组名是这块内存的首地址,可以通过指针来访问它,数组与指针可以灵活转换。

int arr[4] = {1,2,3,4};
int* p = arr;  //arr本身类型就是 int*
相当于
int* p = &arr[0];  //第一个元素的地址 

指针加减法:

  • 指针加法:后移n个元素
  • 指针减法:前移n个元素

指针与数组之间的关系:

  • 用p指向数组arr中的任意一个元素 p = arr+3p = &arr[3]

  • 给数组元素赋值:arr[3] = 10;*(arr+3) = 10int* p = arr+3; *p = 10;

  • 把p可以当成数组使用:

    int* p = &arr[1];
    p[0] = 0xAA; //p[0]:自p开始的第0号元素,即arr[1]
    p[1] = 0xBB; //p[1]:arr[2]
    
  • 数组的遍历

    int arr[4];
    for(int i=0;i<4;i++)
    {printf("%d \n",arr[i]);
    }int arr[4];
    for(int* p = arr; p<arr+4; p++)
    {
    printf("%d \n",*p);
    }
    
  • 越界访问(运行错误)

指针作为函数的参数

可以把指针作为函数的参数,把一个内存地址传给一个函数(传址
使用指针作为参数,可以实现两种功能:

  • 读取上一层函数中变量的值 *p
  • 可以修改上一层函数中变量的值 *p(普通的参数无法实现值修改)

传递数组作为参数,数组名,实质是一个指针类型,传递数组,就是传递指针。将数组信息传给一个函数,需要传递数组首地址(一片连续内存的地址)和数组长度(这块内存上存储的对象个数)。
下面两种形式完全等价:

int avg(int* p, int len)
int avg(int p[],int len)

指针作为函数的参数的作用:

  • 当需要返回多个值的时候,return只能返回一个值,若一个函数需要返回多个值,必须使用指针参数(输出参数)
  • 效率问题:传值与传地址,

const指针

在普通指针类型前面,加上const修饰

const int* p;
const char* p;

有无const的区别:

  • 不加const: 可读可写

    int a = 10;
    int* p = &a;
    *p = 11; //可写
    int b = *p;  //可读
    
  • 加const修饰

    int a = 10;
    const int* p = &a;
    *p = 11; //错!!!,不可写
    int b = *p; //可读 
    

所以const修饰常用限定函数的参数,有的是只读 的输入参数,有的是可以修改的输出参数。当不需要修改内存时,在指针前面加上const修饰,避免不小心的错误。

指针的安全使用

指针只允许指向两个方向:

  • 指向变量,数组
  • 指向0 (NULL) 空指针 此时也不能用*操作,不过可以作为程序判断。

当一个指针未赋值时,其值为随机值,刺实指向一个随机内存地址,称为野指针

好习惯:初始化指针为空指针。