【C语言】深入理解指针(1)

1.内存与地址

  1. 计算机CPU处理数据时,所需数据是从内存中读取的,处理后的数据也会放回内存中,而内存管理的方式就是把内存划分为一个个的内存单元,每个内存单元占一个字节,并且每个内存单元都有相应的编号(比如我们的宿舍都有相关编号,这样方便我们通过编号找到相应宿舍,也方便管理,而一个字节等于8个比特位,相当于每一个宿舍都有8个学生),这样方便CPU找到需要处理的数据。
  2. C语言中  地址=指针=内存单元编号

2.指针变量与地址

1.&符号(取地址操作符)

&符号用于得到对应变量的地址

#include<stdio.h>
int main()
{
    int a=4;  //整型占4个字节
    printf("%p",&a);
    return 0;
}

&a取出的是a所占4个字节中地址较小的字节的地址

虽然整型变量占四个字节,但是我们只要知道了一个字节的地址,顺藤摸瓜也可以访问到四个字节

2.指针变量和解引用操作符(*
  • 指针变量:用于存储地址的值(也就是内存单元的编码)
  • 指针变量也是一种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会被理解为地址
int a=4;
int* p=&a;
  • int*  是指指针变量的类型,也就是p的类型,int 是指p所指向的对象的类型 
  •  *  解引用操作符:可以通过地址找到地址所指向的对象(只是地址所指向的地方对应的值,而不是某个变量)
    int a=100;
    int *pa=&a;
    *pa=0;
    
  • 这里a的地址是pa,而解引用操作符把pa所指向的地方找到,并且修改,此时a地址是pa,所以a的值就改变了
  • 指针变量的大小:指针变量大小取决于地址大小,32位平台下是32个比特位,64位平台下是64个比特位。注意指针变量大小与类型无关,在相同平台下,大小都是相同的

3.指针变量类型的意义

1.指针的解引用
//代码1

int n=0x11223344;
int* p=&n;
*p=0;



//代码2

int n=0x11223344;
char* p=&n;
*p=0;

 调试我们可以看到,两段代码对比可以看到代码一通过解引用改变了四个字节的内容,而代码二通过解引用只改变了一个字节

结论:指针的类型决定它对几个字节有权限。

2.指针+-整数

所以,指针的类型也决定了指针向前或者向后走一步有多大(多少个字节)

3.void*指针
  • 是无具体类型的指针,可以接受任意类型指针,但是不可以直接进行解引用操作,也不能进行+-运算

  • int类型的变量的地址不能赋值给char*指针,而使用void*不会有这种不兼容问题 

4.const修饰指针

1.修饰变量
const int n=20;
n=1;//n不能被修改,不符合语法规则

n本质为变量,是可以修改的,不过加上了const之后,语法受到了限制,不能直接修改n变量

int*p=&n;
*p=0;

 但是可以通过地址修改n变量

2.修饰指针变量
  • const放在 * 的左边时,修饰的是*p,保证指针指向的内容不能改变,但是指针变量本身可以改变
  • const放在 * 的右边时,修饰的是p,保证指针的指向不变,即p不变,但是指针指向的内容可以改变

5.指针运算

1.+-整数运算

可以根据运算的指针变量的类型看整数的加减是操作几个字节

2.指针+-运算

两个指针相减一般用于需要一个指针移动时,通过初末指针的位置差判断移动了几个单位(两个指针类型要相同,每个单位大小为它们指向的对象的大小)

3.指针的关系运算

实际上就是比较指针变量(内存单位编号)的大小,一般用于循环

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	while (p < arr + sz)
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

6.野指针

野指针就是指针指向的位置是不可知的,随机的,不正确的,没有明确限制的

1.原因
  • 指针未初始化
  • 指针越界访问
  • 指针指向的空间释放
2.如何规避野指针
  • 指针初始化
  • 小心指针越界
  • 指针不再使用时,即使置NULL
  • 避免返回局部变量地址

7.assert断言

由头文件  assert.h  包含

assert(p!=NULL);

 若括号内返回为假,直接报错,中断程序

如果已经确认程序没有问题,可以加预处理  #define DEBUG   编译器会禁止用一切assert语句

8.指针的使用和传值调用

当我们定义一个函数时,如果形参不是指针,而只是一个变量,那么形参只会拷贝一份与实参大小相同的变量,当函数调用结束,形参被销毁,实参不会受到影响

#include<stdio.h>

void swap(int x, int y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int x = 2;
	int y = 3;
	swap(x, y);
	return 0;
}

这个时候我们可以使用指针,通过地址改变它们的值

#include<stdio.h>
void swap(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}

int main()
{
	int x = 2;
	int y = 3;
	int* px = &x;
	int* py = &y;
	swap(px, py);
	printf("%d %d ", x, y);
	return 0;
}

此时调试运行一下就知道两个变量的值改变了

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值