Lesson 12 指针2

本文讲解了指针的变量大小计算、类型意义、运算规则(包括指针加减整数和指针间元素计算),以及const修饰指针的含义。还探讨了野指针的成因,并通过实例演示了字符串左旋的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

指针2

这节课继续讲指针相关的知识。

指针变量大小的计算

使用sizeof就可以计算出指针变量的大小。但其实没必要,指针变量的大小是根据环境来的,32位机器就是32bit,4个Byte,64位则是8个Byte。这里也可以理解寻址空间为什么和位数有关。
这里一定要注意,指针类型只是决定指针指向数据的类型,并不是说不同类型的指针变量就必须占用不同的空间。

指针类型的意义

指针类型决定了指针访问内存的方式。
看一下代码:

//代码1
int n = 0x11223344;
int* pi = &n;
*pi = 0;
//代码2
int n = 0x11223344;
char* pc = (char*)&n;
*pc = 0;

上述代码中,代码1是将n改成了0,代码2则是将n的第一个字节改成了0。同样的空间,由于指针类型的不同,导致最后结果的不同。

指针的运算

指针+ - 整数

指针±整数是与其类型相关的。例如一个int* 的指针+1,那么地址会+4,而一个char*类型的指针+1,地址只会+1。这也是另一个指针类型的作用。

指针-指针

这样的结果是计算两个指针之间有多少个元素。使用这种计算的时候,有两个限制:

  1. 两个指针必须是指向同一片空间;
  2. 指针类型必须一致;
    看一下代码:
int arr[10] = {0};
int* p1 = &arr[0];
int* p2 = &arr[4];
int ret = p2-p1;

这里ret的值就是4,表示arr[0]和arr[4]之间有4个元素。

指针的关系运算

指针是可以比较大小的。看一下代码:

int arr[5] = {1,2,3,4,5};
int* p = &arr[0];
int sz = sizeof(arr)/sizeof(arr[0]);
while(p<arr+sz)
{
	printf("%d ",*p)
	p++;
}

上面的代码就是将数组arr中每一个元素都打印出来,注意while循环的条件使用了指针的关系运算。

const修饰指针

const修饰指针根据其位置不同,有以下两种效果:

  1. const位于*左边:修饰的对象是*p,这表示指针指向对象的值是不能被改变的;
  2. const位于*右边:修饰的对象是p,这表示指针指向的对象是不能被改变的;
    举个例子:
int m = 10;
int n = 20;
const int* p1 = &m;
*m = 0;//报错,因为*m是无法改变的
int* const p2 = &n;
p2 = &m;//报错,p2所指的对象是无法改变的

这里只看const*的相对位置,顺序是无所谓的。

野指针的成因

野指针是指指针指向的位置是不可知的。其成因有:

  1. 指针没有初始化:指针在创建后如果没有初始化,那么它指向的位置就是随机的;
  2. 指针越界访问:例如数组指针访问到数组范围之外的时候,指针就成了野指针;
  3. 指针指向空间的释放:这里看一下下面的代码。
int* test()
{ int n = 1;
	....
	return &n;
}

这里的n是函数内部的局部变量,在函数调用完成后,会释放这块空间,那么返回的&n就成了野指针。

一个小练习:字符串左旋

来源是今天的作业,字符串左旋:
实现一个函数,可以左旋字符串中的k个字符。
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
想了不少时间。下面先说说思路:

  1. 最简单的想法就是每次左旋1个字符,循环k次。ABCD先变成BCDA然后再变成CDAB。但感觉这样效率比较低,就继续想;
  2. 经过老师的提示,可以使用这个思路。首先对字符串逆序,然后把字符串分成0~k-1k~sz-1两部分,再分别对这两部分逆序。例如想逆序ABCDEF的3个字符,先变成FEDCBA,然后变成DEFCBA,最后变成DEFABC。这个思路就比较好了,不需要多次循环,那么就可以代码实现了:
#include <string.h>
void reverse_str(char* start, char* end)
{
	while (start < end)
	{
		*start = *start ^ *end;
		*end = *start ^ *end;
		*start = *start ^ *end;
		start++;
		end--;
	}
}

void left_votex(char* ch, int sz, int n)
{
	n = n%sz;
	char* flag = ch + n - 1;
	reverse_str(ch, ch + sz - 1);
	reverse_str(ch, flag);
	reverse_str(flag + 1, ch +sz - 1);

}

int main()
{
	char ch[] = "ABCDEF";
	printf("左旋前:%s\n", ch);
	int n = 0;
	int sz = strlen(ch);
	printf("请输入字母个数:>");
	scanf("%d", &n);
	left_votex(ch, sz, n);
	printf("左旋后:%s\n", ch);
	return 0;
}

逆序部分参考之前的字符串逆序,其余实现起来就没有那么难了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值