指针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
。这也是另一个指针类型的作用。
指针-指针
这样的结果是计算两个指针之间有多少个元素。使用这种计算的时候,有两个限制:
- 两个指针必须是指向同一片空间;
- 指针类型必须一致;
看一下代码:
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修饰指针根据其位置不同,有以下两种效果:
- const位于
*
左边:修饰的对象是*p
,这表示指针指向对象的值是不能被改变的; - const位于
*
右边:修饰的对象是p
,这表示指针指向的对象是不能被改变的;
举个例子:
int m = 10;
int n = 20;
const int* p1 = &m;
*m = 0;//报错,因为*m是无法改变的
int* const p2 = &n;
p2 = &m;//报错,p2所指的对象是无法改变的
这里只看const
和*
的相对位置,顺序是无所谓的。
野指针的成因
野指针是指指针指向的位置是不可知的。其成因有:
- 指针没有初始化:指针在创建后如果没有初始化,那么它指向的位置就是随机的;
- 指针越界访问:例如数组指针访问到数组范围之外的时候,指针就成了野指针;
- 指针指向空间的释放:这里看一下下面的代码。
int* test()
{ int n = 1;
....
return &n;
}
这里的n
是函数内部的局部变量,在函数调用完成后,会释放这块空间,那么返回的&n
就成了野指针。
一个小练习:字符串左旋
来源是今天的作业,字符串左旋:
实现一个函数,可以左旋字符串中的k个字符。
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
想了不少时间。下面先说说思路:
- 最简单的想法就是每次左旋1个字符,循环k次。ABCD先变成BCDA然后再变成CDAB。但感觉这样效率比较低,就继续想;
- 经过老师的提示,可以使用这个思路。首先对字符串逆序,然后把字符串分成
0~k-1
和k~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;
}
逆序部分参考之前的字符串逆序,其余实现起来就没有那么难了。