C语言学习笔记——6(指针)

目录

内存的基本概念

变量与地址

指针的本质

指针就是内存地址               

指针变量,是用来存放内存地址的变量

指针的定义

        类型 *指针变量名;

通过指针修改变量

指针的解引用

​编辑

int *p 与 (*p)的区别

 int *p - 指针声明

 (*p) - 指针解引用

指针运算

指针的算术运算

普通加减

自增自减

int *p和char *p有什么区别

1. 解引用后的类型

2. 指针算术运算的步长

指针和数组

注意事项:

数组名与指针变量的深度对比

指针和二维数组

使用一级指针遍历二维数组

行指针

什么是行指针?

二维数组名的本质

 基本语法

初始化

用行指针遍历二维数组

字符指针与字符串

对字符串进行一个遍历,并大小写进行转换

char s[]="hello" 与 char *s="hello" 的区别

实现字符串的连接


内存的基本概念

内存是计算机用于临时存储程序和数据的硬件,具有以下特点:

  • 按字节编址:每个字节有唯一地址

  • 随机访问:可按地址直接访问任意位置

  • 易失性:断电后数据丢失

变量与地址

a是变量,&a是地址

int a = 10;        // 在栈上分配4字节内存

// 查看变量地址
printf("a的地址: %p\n", &a);    // 输出0x7ffc5a3b2a10

指针的本质

  • 指针就是内存地址               

  • 指针变量,是用来存放内存地址的变量

指针的定义

        类型 *指针变量名;

通过指针修改变量

指针的解引用

int *p 与 (*p)的区别

  •  int *p - 指针声明

  •  (*p) - 指针解引用

p一指针变量,它的内容是地址量

*p一指针的目标,它的内容是数据(a)

&p一指针变量占用的存储区域的地址,是个常量

int a = 4211;
int *p = &a;

printf("p = %p\n", p);      // p的内容:a的地址
printf("*p = %d\n", *p);    // *p的值:a的内容
printf("&p = %p\n", &p);    // &p的值:p自身的地址

指针运算

指针运算是以指针所存放的地址作为运算量而进行的
指针运算的实质就是地址的计算

指针的算术运算

普通加减

#include <stdio.h>
int main()
{
        int a = 4211;
        int *p = &a;
        (*p)++;
        printf("a=%d,p=%p\n",a,p);
        printf("&a=%p,&p=%p\n",&a,&p);
        printf("&a+1=%p\n",&a+1);
        printf("p+1=%p\n",p+1);
        printf("&p+1=%p\n",&p+1);
        return 0;
}
a=4212,p=0x7ffdb245383c
&a=0x7ffdb245383c,&p=0x7ffdb2453840
&a+1=0x7ffdb2453840
p+1=0x7ffdb2453840
&p+1=0x7ffdb2453848

观察规律:

#include <stdio.h>
int main()
{
        int a[] = {4,2,1,1};
        int *p=a;

        printf("*p:%d,                    p:%p\n",*p,p);
        printf("*(p+2):%d,                p+2:%p\n",*(p+2),p+2);
        printf("(*(p+2)-*(p+1)):%d,       (p+2)-(p+1):%p,%d\n",(*(p+2)-*(p+1)),(p+2)-(p+1),(p+2)-(p+1));
        return 0;
}
*p:4,                    p:0x7ffe32eaadf0
*(p+2):1,                p+2:0x7ffe32eaadf8
(*(p+2)-*(p+1)):-1,       (p+2)-(p+1):0x1,1

自增自减

运行*p++,(*p)++这两个的结果是否一样

点此处可以查看第七大点优先级,复习之前的知识

第一行*p与p,写出了a的值和a的位置

第二行*p与p,写出了a的位置+4byte的值和a的位置+4byte

                      因为这个位置没有定义变量,所以值不确定

                       *p++,先改变位置,在进行解引用,解出了其他地址的值

第三行*v与v,写出了a的值+1和a的位置

                     (*v)++,先进行解引用,在改变变量的值

int *p和char *p有什么区别

1. 解引用后的类型

  • int *p:通过 *p 访问到的是一个 int 类型的值,通常占 4 个字节。

  • char *p:通过 *p 访问到的是一个 char 类型的值,占 1 个字节。

2. 指针算术运算的步长

指针进行 p++p + n 等运算时,移动的字节数取决于指向类型的大小。

  • int *pp++ 会向前移动 sizeof(int) 个字节(通常是 4)。

  • char *pp++ 会向前移动 sizeof(char) 个字节(即 1)。

因此,用 int * 遍历数组时一次跳过一个整型元素,用 char * 则可以逐个字节遍历内存。

指针和数组

数组指针是指数组在内存中的起始地址

数组元素的地址是指数组元素在内存中的起始地

注意事项:

指针变量和数组名都是地址量

数组名与指针变量的深度对比

对比维度数组名 (如 int arr[5])指针变量 (如 int *p)
本质地址常量(符号常量)地址变量
内存占用整个数组的大小固定大小(4/8字节)
可修改性不可修改(常量)可修改
类型含义代表整个数组结构代表一个地址存储单元
&操作得到整个数组的地址(值相同,类型不同)得到指针变量自身的地址
sizeof整个数组的大小指针本身的大小

指针和二维数组

使用一级指针遍历二维数组

行指针

什么是行指针?

行指针也称为数组指针,是指向整个一维数组的指针,而不是指向单个元素。它存储的是整个一维数组的地址。

<数据类型>(*<指针变量名>)[表达式];
int a[3][4];      // 二维数组
int (*p)[4];      // 行指针,指向包含4个int的数组

二维数组名的本质

int a[3][4];
// a 的类型是 int (*)[4],即行指针类型
// a + 1 移动一行(4个int,16字节,假设int为4字节)
// 注意:a 是常量指针,不能修改(如a++非法)

方括号中的常量表达式表示指针加1,移动几个数据。

 基本语法

// 语法:<数据类型> (*<指针变量名>)[列数];
int (*p)[4];       // 指向包含4个int的数组
float (*fp)[10];   // 指向包含10个float的数组

// 注意:括号是必须的,因为[]的优先级高于*
// 如果没有括号,int *p[4]; 则表示指针数组(一个数组,其元素为int指针)

初始化

int a[3][4];
int (*p)[4] = a;   // 将二维数组名赋值给行指针,即指向第一行

// 也可以指向某一行
int (*p2)[4] = &a[1]; // 指向第二行(行索引从0开始)

用行指针遍历二维数组

字符指针与字符串

对字符串进行一个遍历,并大小写进行转换

当一个字符指针指向一个字符串常量时,不能修改指针指向的对象的值

char s[]="hello" 与 char *s="hello" 的区别

这两个声明看起来相似,但本质完全不同。以下是它们的详细对比:

特性char s[] = "hello";char *s = "hello";
类型字符数组字符指针
内存分配在栈上分配数组空间指针变量在栈上,指向字符串常量(存储在只读区域)
存储位置数组存储在栈/数据段(取决于声明位置)指针变量在栈上,字符串常量在只读数据段
可修改性可以修改数组内容(如 s[0]='H'不可修改字符串内容(尝试修改会导致未定义行为)
sizeof() 结果返回数组大小(6,包含'\0')返回指针大小(通常是 4 或 8 字节)
赋值操作不能对数组名整体赋值(s = "world" 错误)可以重新赋值指向其他字符串(s = "world" 正确)
指针运算

数组

名不是左值,不能自增(s++ 错误)

指针可以自增(s++ 正确)
内存管理自动管理生命周期需要确保指针指向有效的内存
作为函数参数退化为指针,传递数组首地址直接传递指针值

实现字符串的连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值