C语言指针强化

目录

1.指针的强制转化

2.const与一级指针和二级指针的结合

第一节:指针的强制转化

引言

强制转化

扩展

 第二节 const与一级指针和二级指针的结合

const与一级指针的结合

例题 

const与二级指针的结合

例题

扩展


第一节:指针的强制转化

引言

Windows系统的存储方式为小端存储模式

小端存储模式:数据中的低字节,存储在低地址中;数据中的高字节,存储在高地址中
大端存储模式:数据中的高字节,存储在低地址中;数据中的低字节,存储在高地址中。

正常情况:

假设有一组数据存储在数组arr中:int arr[] = {1,2,13,14};那么该组数据如何在内存中存储呢?

 如上图所示,即为数据的存储方式

当想读取不同的数据时,即可通过指针实现,首先定义一个指针:int* p = arr;(数组名arr代表该数组首元素的地址,变量p存储将其进行存储)

即指针首先访问数组元素的首地址,对第一个数据进行读取,当想读第二个数据时,通过p+1即可完成,即*p+1 = 2

指针由第一个位置移动至第二个位置,进而读取第二个数据:2

在这里强调:p+1,即指针p向右移动了1个单元格,而1个单元格的大小由指针指向的变量的类型决定,此处,int为四个字节,故而移动四个小格。

强制转化

int *p = arr;

char *q = p;(这句语句正确吗?)

显然错误,此时接受该指针变量的类型已经发生了改变,所以需要进行强制转换;

int *p = arr;

char *q = (char*)p;

通过强制转换来保证语法的正确性,但同时结果也发生了改变:

(char*)p+1的结果肯定不是2了,那是多少呢?

 

char类型为1个字节,所以1个小格为一个单元格,故而,(char*)p + 1 = 0;

#include <stdio.h>
int main()
{
	int arr[4] = { 1,2,13,14 };
	int* p = arr;
	char* q = (char*)p + 1;
	printf("%d", *q);
	return 0;
}

 如果将数据类型提升为 long long,那结果又会是如何呢?

 long long为8字节,所以指针移动如上,所以结果是d吗?不,进行数据读取时也是按照数据类型进行读取,所以应该读取为8个字节的数,那是否为d e?也不是。

#include <stdio.h>
int main()
{
	int arr[4] = { 1,2,13,14 };
	int* p = arr;
	long long* q = (long long*)p + 1;
	printf("%llx", *q);
	return 0;
}

 结果为何为e 00 00 00 0d?

这与栈的内存开辟与数组存储的方式以及小端模式有关:

首先要开辟内存空间(X86系统分配内存空间为4G),局部变量内存的开辟位于栈区(栈区在Win系统下为1M,在Linux系统中为10M)

     栈内存开辟:从高地址到低地址进行内存开辟;

     数组内存:从低地址到高地址进行存储。

由于Win系统的小端存储模式,故而,低字节的数据存储于低地址处,低字节的数据存储于低地址处,但我们一般读取数据时,应该从高位向地位读取,从而我们读取的顺序为从高地址到低地址进行读取。

所以读取的结果为 e 00 00 00 0d

总结:指针+num 《=》 指针偏移sizeof(指针指向的类型)* num 个字节

扩展

存储空间内的“地雷”

在数组中,一般位于数组的头部与尾部“地雷”以“cccc”四字节的形式出现,若访问到此处,程序可能会崩掉或者出错。

例:定义两个变量:

int a = 0;

int b = 0;

则两个变量之间差多少个字节?

首先用代码实现:

#include <stdio.h>
int main()
{
	int a = 0;
	int b = 0;
    printf("%p\n",&a);
    printf("%p\n",&b);
	printf("%d", &a - &b);
	return 0;
}

答案为3;

由于int类型为4字节,所以两个变量之间相差12个字节,内存空间分配如下:

         

同时也可以通过VS 2019自行调试:

1.给出断点;

2.开始调试;

3.进入窗口;

4.点击内存并选择;

5.输入"&+变量"。

       

 第二节 const与一级指针和二级指针的结合

const与一级指针的结合

(const与变量结合使其变为常变量,从而使其变为常量,即不能通过赋值方式改变变量的值)

首先定义一个一级指针:int* p = &a;

当const与其结合使用时,共分为三种情况:

1.const放在指针前:const int* p = &a;

const放在指针前,意味着const作用于(*p),即不能通过对指针变量p解引用的方式改变a的值

但是,对变量p不产生影响,p可以改变,去存储其他变量的地址。

2.const放在指针后,变量前:int* const p = &a;

 const放在指针后,意味着const作用于p本身,即指针变量只能存储变量a的地址,指针变量p不能指向其他变量

3.指针前与指针后都放const,则二者皆不能改变:const int* const p = &a;

此种情况下,指针变量与指针皆为常变量,所以都没有办法改变

例题 

给出条件,判断语句的对错:

int a = 0,b = 0;
const int* p = &a;
*p = 10; //(1)
p = &b;  //(2)

int*const p = &a;
*p = 10; //(3)
p = &b;  //(4)

const int* const p = &a;
*p = 10; //(5)
p = &b;  //(6)

const int a = 0;
const int b = 0;
int *p = &a; //(7)

(1)错(2)对

原因:const对指针*p 起作用,则*p不能通过解引用的方式来改变a的值,但是指针变量并没有受到限制,所以指针变量p的值可以被改变

(3)对(4)错

原因: const作用于p本身,即指针变量只能存储变量a的地址,指针变量p不能指向其他变量,但是*p并没有受到限制,所以可以通过解引用的方式改变a的值

(5)错(6)错

原因:二者皆受到限制

(7)错

原因:此时a,b变量皆为常变量,若(7)式成立,则意味着可以通过解引用的方式改变a的值,所以错位,正确语句应该显示不能通过解引用的方式来改变a的值: const int *p = &a;

const与二级指针的结合

首先定义一个二级指针:int** s = &p;

与const结合时,共有六种情况:

1.const int **s = &p; 

2.int * const *s = &p;

3.int **const s = &p;

4.const int* const * s = &p;

5.const int* const * const s = &p;

6.int*const* const s = &p;

例题

int a = 0;
int b = 0;
const int *p = &a;
int* const q = &a;
int** s1 = &p;
s1 = &q;
**s1 = 20; //(1)
const int **t1 = &p;
t1 = &q; //(2)
*t1 = &b; //(3)
**t1 = 10; //(4)
int *const*s2 = &p;
*s2 = &a; //(5)
**s2 = 100; //(6)

(1) 对 对**s1没有任何限制;

(2)对 对t1没有任何限制;

(3)对 对*t1没有任何限制;

(4)错 const int **t1 = &p;不能通过对t1解引用的方式改变a的值;

(5)错 int* const*s2 = &p;不能通过对s2解引用的方式改变p的值;

(6)对 对s2没有任何限制。

扩展

const ,指针与字符串常量

首先判断这条语句是否正确:

char* str = "hello";

用编译器实现:

显然无法实现,因为hello是一个字符串常量

字符串常量与全局变量,静态内存等等共同存储在数据区中,即(.data)(局部变量存储在栈区,动态内存存储在堆区)

而语句意思为:str保存字符串常量存储的地址,若上试成立,则意味着可以通过解引用的方式改变字符串常量中的字符: *str + 1 = ‘a’;显然错误

正确的应为:const char *str = "hello";

练习:

const int a = 0;
int b = 0;
const int* p = &a;
p = &b; //(1)
*p = 10; //(2);
const int* const* s = &p;
*s = &a; //(3)
**s = 10; //(4)
const int **t = &p;(5)      
*t = &a; //(6)
const int* const* t = &p;
**t = 10; //(7)
*t = &a;  //(8)
p = &a;   //(9)



 分析:根据题干,首先,变量a为一个常变量,不能被修改,b为一个变量,*p为常变量,不能通过解引用的方式改变变量的值;

(1)对 p没有任何限制;//此时p已经指向变量b

(2)错 不能通过解引用的方式改变b的值;

(3)错 不能通过解引用的方式改变p的值;

 (4)   错  不能通过解引用的方式改变b的值;

(5)对 *p在以上语句中已经被限制,所以不加const,即可通过解引用两次t,改变b的值,但是当解引用一次时*t = p,解引用第二次时,*p则无法进一步解引用,所以不能通过该种方式进行改变b的值,所以在**t前加上const;

(6)对 *t无限制;

(7)错;

(8)错 **t与*t都被限制;

(9)p本身不受限制。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值