C语言卡在指针哪里,C语言 指针

本文详细介绍了C语言中的指针基础知识,包括内存地址、指针变量、数据存储格式、指针类型及运算。讨论了指针与数组、字符串的交互,以及const修饰指针的作用。此外,还探讨了指针数组的概念和操作。通过对指针的深入理解,有助于提升C语言编程能力。
摘要由CSDN通过智能技术生成

一、C语言 指针基础

1、内存地址

1、内存含义

存储器:计算机的组成中,用来存储程序和数据,辅助CPU进行运算处理的重要部分。

内存:内部存贮器,暂存程序/数据——掉电丢失 SRAM、DRAM、DDR、DDR2、DDR3。

外存:外部存储器,长时间保存程序/数据—掉电不丢ROM、ERRROM、FLASH(NAND、NOR)、硬盘、光盘。

2、内存是沟通CPU与硬盘的桥梁

暂存放CPU中的运算数据

暂存与硬盘等外部存储器交换的数据

3、物理存储器和存储地址空间

有关内存的两个概念:物理存储器和存储地址空间

4、物理存储器:实际存在的具体存储器芯片

主板上装插的内存条

显示卡上的显示RAM芯片

各种适配卡上的RAM芯片和ROM芯片

5、存储地址空间:对存储器编码的范围。我们在软件上常说的内存是指这一层含义

编码:对每个物理存储单元(一个字节)分配一个号码

寻址:可以根据分配的号码找到相应的存储单元,完成数据的读写

6、内存地址

将内存抽象成一个很大的一维字符数组。

编码就是对内存的每一个字节分配一个32位或64位的编号(与32位或者64位处理器相关)。

这个内存编号我们称之为内存地址。

7、内存中的每一个数据都会分配相应的地址

char:占一个字节分配一个地址

int: 占四个字节分配四个地址

float、struct、函数、数组等

72f28cac5036336a7b80b672ecf0b32d.png

2、指针变量

一、概述

内存区的每一个字节都有一个编号,这就是“地址”。

如果在程序中定义了一个变量,在对程序进行编译或运行时,系统就会给这个变量分配内存单元,并确定它的内存地址(编号)

指针的实质就是内存“地址”。指针就是地址,地址就是指针。

指针是内存单元的编号,指针变量是存放地址的变量。

通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。

4dfcdfd7001656e3f9d37cec88bb674f.png

二、数据存储格式

注:windos电脑在做数据存储时采用小端对齐。

注:Linux 电脑在做数据存储时采用大端对齐。

三、定义说明

指针也是一种数据类型,指针变量也是一种变量

指针变量指向谁,就把谁的地址赋值给指针变量

“*”操作符操作的是指针变量指向的内存空间

注意:&可以取得一个变量在内存中的地址。但是,不能取寄存器变量,因为寄存器变量不在内存里,而在CPU里面,所以是没有地址的。

注意:&是取地址符号是升维度的、*是取值符号是将维度的。

注意:在定义指针类型一定要和变量的类型对应上。

四、案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//定义指针变量存储变量地址

int a = 10;//指针类型:数据类型*

int*p;

p= &a;//通过指针间接改变变量的值

*p = 100;

printf("%p", &a);

printf("%p", p);

printf("%d", a);

printf("%d", *p);return 0;

}

指针变量 使用案例:int类型指针修改值

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{char ch = 'a';char* p = &ch;//所有指针类型存储都内存地址,内存地址都是一个无符号十六进制整形数//32位操作系统所有指针类型:内存占用4字节//64位操作系统所有指针类型:内存占用8字节

printf("%d", sizeof(int*));

printf("%d", sizeof(char*));return 0;

}

指针变量 使用案例:指针在内存中占用字节大小

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{int arr[] = { 1,2,3,4,5,6,7,8,9,10};//P 和 arr 不同点//指向数组指针

int* p =arr;//相同点//p[i]//*(p+i)//不同点//p 是变量、arr是常量//p 是一个指针4个字节大小//arr 是一个数组是40个字节大小

printf("指针类型大小%d", sizeof(p));

printf("数组大小%d", sizeof(arr));//数组作为函数参数会化为指针、丢失数组的精度//通过 int* 将指针变为值//void BubbleSort(int arr[])//void BubbleSort(int* arr[],int len)

return 0;

}

指针变量 使用案例:指针与变量不同点

3、野指针

指针变量也是变量,是变量就可以任意赋值,不要越界即可(32位为4字节,64位为8字节),但是,任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。野指针和有效指针变量保存的都是数值,为了标志此指针变量没有指向任何变量(空闲可用)

int a = 100;int *p;

p= a; //把a的值赋值给指针变量p,p为野指针, ok,不会有问题,但没有意义

p= 0x12345678; //给指针变量p赋值,p为野指针, ok,不会有问题,但没有意义

*p = 1000; //操作野指针指向未知区域,内存出问题,err

案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//野指针 -> 指针变量指向一个未知的空间//不建议将一个变量的值直接赋值给指针//程序中允许存在野指针

int* p = 100;//操作系统将0-255作为系统占用不允许访问操作//操作野指针对应的内存空间可能报错

printf("%d", *p);return 0;

}

野指针 使用案例

4、空指针

C语言中,可以把NULL赋值给此指针,这样就标志此指针为空指针,没有任何指针。

//空指针

int *p =NULL;//NULL是一个值为0的宏常量:

#define NULL ((void *)0)

案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//空指针是指内存地址编号为0的空间

int* p =NULL;//操作空指针对应的空间一定会报错

*p = 100;

printf("%d", *p);//空指针可以用作条件判断

if (p ==NULL)

{

}return 0;

}

空指针 使用案例

5、万能指针

void *指针可以指向任意变量的内存空间。

案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{int a = 10;//万能指针可以接受任意类型变量的内存地址

void * p = &a;//再通过万能指针修改变量的值时,需要找到变量对应的指针类型

*(int*)p = 100;

printf("%d", a);

printf("%d", *(int*)p);//printf("万能指针在内存占得字节大小:%d

", sizeof(void*));

return 0;

}

万能指针 使用案例

6、const 修饰指针

const 修饰可以约束指针类型或值得修改,但使用+1级别指针也可以让const无效。

案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//1、//常量:不允许修改//存储空间:栈区(可指针间接修改)

const int a = 10;//指针间接修改常量值

int* p = &a;*p = 100;

printf("%d", a);//2、//const 修饰指针类型(内存空间)

int a = 10;int b = 20;const int* p = &a;//可以修改指针变量的值//不可以修改指针内存空间的值:*p = 100;

p = &b;

printf("%d", *p);//3、//const 修饰指针变量

int c = 10;int d = 20;int* const p = &c;//可以修改指针类型(内存空间)的值//不可以修改指针内存空间的值:p = &d;

*p = 100;

printf("%d", *p);//4、//const 修饰指针变量、类型(内存空间)//只读指针

int e = 10;int f = 20;//不可以修改指针内存空间的值:*p = 100;//不可以修改指针内存空间的值:p = &f;

const int* const p = &e;//二级指针操作//可通过二级指针修改一级指针内存空间的值:

int** pp = &p;//*pp是一级指针的值(内存空间)

*pp = &b;//**pp是变量的值、**代表将了一个维度

**pp = 100;

printf("%d", *p);return 0;

}

const修饰指针 使用案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#include #include#include

int main(void)

{//const修饰一个变量为只读

const int a = 10;//a = 100;//err//指针变量, 指针指向的内存, 2个不同概念

char buf[] = "aklgjdlsgjlkds";//从左往右看,跳过类型,看修饰哪个字符//如果是*, 说明指针指向的内存不能改变//如果是指针变量,说明指针的指向不能改变,指针的值不能修改

const char *p =buf;//等价于上面 char const *p1 = buf;//p[1] = '2';//err

p = "agdlsjaglkdsajgl"; //ok

char * const p2 =buf;

p2[1] = '3';//p2 = "salkjgldsjaglk";//err//p3为只读,指向不能变,指向的内存也不能变

const char * const p3 =buf;return 0;

}

const修饰指针 使用案例:2

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//定义int类型

const int a = 10;//直接不可以修改//a = 100;//err//通过一级指针修改

int* p = &a;*p = 100;//定义char类型

char ch1[] = "hello";char ch2[] = "hello";//指向常量指针:可以修改指针变量的值、不可以修改指针变量指向内存空间的值

const char* p =ch1;//*p = 'm';//err//p = ch2;//ok//p[2] = 'm';//err//定义char类型

char ch3[] = "hello";char ch4[] = "hello";//常量指针:可以修改指针变量指向内存空间的值、不可以修改指针变量的值

char* const p =ch3;//p = ch4;//err//p[2] = 'm';//ok//*(p + 2) = 'm';//ok//定义char类型

char ch5[] = "hello";char ch6[] = "hello";//不可修改变量与内存

const char* const p =ch5;//p = ch6;//err//p[2] = 'm';//err//*p = 'm';//err//二级指针

char** p1 = &p;//*p1 = ch2;//ok//*(*p1+1) = 'm';//ok

return 0;

}

const修饰指针 使用案例:3

二、C语言 指针使用

1、指针类型运算

指针计算不是简单的整数相加

如果是一个int *,+1的结果是增加一个int的大小

如果是一个char *,+1的结果是增加一个char大小

案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{int arr[] = { 1,2,3,4,5,6,7,8,9,10};//数组名是一个常量 不允许赋值//数组名是数组首元素地址//aar = 100;//err//创建指针变量

int*p;

p=arr;

printf("%p", p);//打印数组第一个值

printf("%d", *p);

printf("%p", arr);//*取值(arr内存地址+1) 、相当于arr[1]

printf("%d", *(arr + 1));//指针类型变量+1:等同于内存地址+sizeof(类型)

printf("%d", *(p + 1));//指针p++:等同于内存地址+sizeof(类型)

*p = 123;

p++;

printf("%p", arr);

printf("%p", p);for (int i = 0; i < 10; i++)

{//打印数组值

printf("%d", p[i]);

printf("%d", *(p +i));//打印数组值

printf("%d", *p++);

}//两个指针相减 得到的结果是两个指针的偏移量(步长)//所有的指针类型 相减结果都是int类型//3c 40 +1 相当于 sizeof(int) 40/sizeof(int)

int step = p -arr;

printf("%d", step);return 0;

}

指针类型运算 使用案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

//方式一:数组方式实现

void my_strcpy01(char* dest, char*ch)

{int i = 0;//非0为真值

while(ch[i])

{

dest[i]=ch[i];

i++;

}

dest[i]= 0;

}//方式二:以指针偏移量

void my_strcpy02(char* dest, char*ch)

{int i = 0;while (*(ch+i))

{*(dest + i) = *(ch +i);

i++;

}*(dest + i) = 0;

}//方式三:以指针运算方式实现

void my_strcpy03(char* dest, char*ch)

{while (*ch)

{*dest = *ch;//指针+1相当于指向数组下一个元素 内存地址变化了sizeof(char)

dest++;

ch++;

}*dest = 0;

}//方式四:以指针加运算方式实现

void my_strcpy04(char* dest, char*ch)

{//第一步:*ch 取值 *dest 取值//第二部:*dest = *ch 赋值//第三部:判断 值是否非0//第四部:ch++ dest++

while (*dest++ = *ch++);

}int main(void)

{//指针运算、字符串拷贝

char ch[] = "hello world";char dest[100];

my_strcpy04(dest, ch);

printf("%s", dest);return 0;

}

指针类型运算 使用案例:指针加法运算

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{int arr[] = { 1,2,3,4,5,6,7,8,9,10};int* p =arr;//指针的加减运算和指针的类型有关

p = &arr[3];

p--;

p--;

p--;//内存地址相差:12 / sizeof(int) = 偏移量

int step = p -arr;//指针操作数组时下标允许时负数//p[-2] = *(p-2);

printf("%d", p[-2]);

printf("%p", p);return 0;

}

指针类型运算 使用案例:指针减法运算

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//指针和运算符的操作

int arr[] = { 1,2,3,4,5,6,7,8,9,10};int* p =arr;//野指针//p = p + arr;//err//p = p*arr;//err//p = p*4;//err//p = p/4;//err//p = p%4;//err//指针判断可以使用、> = < ? && || ...//p = &arr[3]//if (p > arr) { printf("真

");}//野指针可以相减//p = 100;//int step = arr - p;

///printf("%d

",step)

return 0;

}

指针类型运算 使用案例:指针符号运算

2、指针数组

指针数组,它是数组,数组的每个元素都是指针类型。

案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//定义数组 数据类型 数据名[元素个数] = {值1,值2}//定义指针数组

int a = 10;int b = 20;int c = 30;int* arr[3] = { &a,&b,&c };//arr[0]:为指针数组地址//*arr[0]:为指针对应值

printf("%d", arr[0]);

printf("%d", *arr[0]);for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)

{//打印数组内每个值

printf("%d", *arr[i]);

}//指针数组大小 = 对应类型 * 元素个数

printf("指针数组大小:%d", sizeof(arr));

printf("指针数组大小:%d", sizeof(arr[0]));return 0;

}

指针数组 使用案例

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

int main(void)

{//指针数组里面元素存储的是指针

int a[] = { 1,2,3};int b[] = { 4,5,6};int c[] = { 7,8,9};//指针数组时一个特殊的二维数组模型//指针数组对应于二级指针

int* arr[] ={ a,b,c };//打印内存地址//arr 是指针数组的首地址

printf("%p", arr[0]);

printf("%p", a);

printf("%p", &a[0]);for (int i = 0; i < 3; i++)

{for (int j = 0; j < 3; j++)

{//通过二维数组方式打印所有值

printf("%d", arr[i][j]);//通过偏移量方式打印

printf("%d", *(arr[i]+j));//通过偏移量与指针运算方式打印

printf("%d", *(*(arr + i) +j));

}

puts("");

}return 0;

}

指针数组 使用案例:2

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#define _CRT_SECURE_NO_WARNINGS#include#include#include#include#include

//数组名做函数参数,函数的形参会退化为指针//通过数组写法实现

void my_strcat01(char* ch1, char*ch2)

{int i = 0;while (ch1[i] != '

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值