一、const修饰指针
1.const修饰变量
我们知道变量的值是可以随时进行赋值改变的,而当一个变量被const修饰时呢?
//演示1.1.1
#include <stdio.h>
int main()
{
int num1 = 0;
num1 = 10; // num1 是可以被修改的
printf("%d\n", num1);
const int num2 = 0;
num2 = 20; // num2 不可以被修改
printf("%d\n", num2);
return 0;
}
这里num1是可以被修改并打印的,但是num2是被const修饰的变量,不可更改,对它进行赋值会导致程序报错。
然而我们也不是就完全没办法改变num2中的值了。运用指针指向num2再进行解引用,就可以对num2中的值进行修改。
这里的目的只是介绍这样一个知识点,但平时编程时并不建议这样做,因为这样实际是在破坏语法规则。
//演示1.1.2
#include <stdio.h>
int main()
{
int num1 = 0;
num1 = 10;
printf("%d\n", num1);
const int num2 = 0;
int* pn = &num2;
*pn = 20;
printf("%d\n", *pn);
return 0;
}
2.const修饰指针
2.1. const在 * 左边
const在 * 左边时,限制的是*pa,即使指针变量pa指向的变量a,不能通过指针pa进行更改。
//演示1.2.1
#include <stdio.h>
int main()
{
int a = 2, b = 4;
const int* pa = &a;
a = 6; //①
pa = &b; //②
*pa = 8; //③
return 0;
}
①可修改,因为a是变量,且没有被const修饰
②可修改,因为const修饰的是*pa而没有限制pa
③不可修改,因为*pa被const修饰,不可更改
2.2. const在 * 右边
const在 * 右边时,限制的是pa,即指针变量pa指向的对象不可以再改变。
还是演示1.2.1中的代码,再看①②③的情况:
①可修改
②不可修改,因为pa被const所限制,指针pa指向的对象是不能变的,只能指向变量a
③可修改,因为*pa并没有受const限制
2.3. const在 * 两边都有
这种情况下,pa和*pa都会受到限制,也就是说,同样在演示1.2.1的代码中,②和③都是不可修改,无法实现的。
二、指针运算
指针的的基本运算有三种,分别是:指针+-整数、指针+-指针、指针的关系运算。
1.指针+-整数
因为数组在内存中是连续存放的,所以只要知道第⼀个元素的地址,顺藤摸瓜就能找到后面的所有元素。
//演示2.1.1
int main()
{
int arr = { 1,2,3,4,5,6,7,8,9,10 };
return 0;
}
于是就有下面这段演示代码:
//演示2.1.2
include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<sz; i++)
{
printf("%d ", *(p+i));//p+i 这⾥就是指针+整数
}
return 0;
}
这里就是通过变量 i 生成遍历数组下标的整数0~9,然后在 p+i 中通过指针+整数的方式,依次从前往后的访问数组元素。
那么自然,我们这段代码也可以这样写:
//演示2.1.3
include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=sz-1; i>=0; i--)
{
printf("%d ", *(p+i));
}
return 0;
}
2.指针-指针
既然指针里存放的地址本质就是一个数,那么自然可以进行减法运算。
//演示2.2.1
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int num = 0;
int* pa = &arr[0];
int* pb = &arr[4];
num = pb - pa;
printf("num = %d\n",num);
return 0;
}
单纯看指针中地址的大小的话,一个整型占4个字节,两个地址间应该相差16个字节才对,但结果为什么是4而不是16呢?
前一篇博客中我们讲到,整型指针的类型是int*,*代表这个变量是指针,而int表示这个指针指向对象的类型是int。
可以这样理解,在指针进行减法运算的时候,它们也受到自己类型的影响,*在表示这个变量是指针,int在表示它是整型变量。
在指针减指针的时候,*让他们中存放的地址相减,而int使这个商表示为多少个int类型的数据。也就是说,在上面演示中,地址相减得16字节,而一个整型是4个字节,所以16/4=4,最终结果就会是4。
再看下面这段代码:
//演示2.2.2
#include <stdio.h>
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}
int main()
{
printf("%d\n", my_strlen("abc"));
return 0;
}
这里我们首先要知道一个点,就是字符串在传参的时候,传递的是字符串首个字符的地址。所以在my_strlen函数中用字符指针来接收传递过来的参数。
不难看出指针s指向字符串首字符,而指针p经过循环后指向了字符串末尾的\0。
经过演示2.1.1的讲解,我们可以知道,这里两个指针p和s中的地址相差了3,而字符类型char的数据占据1个字节,所以3/1=3,最终结果就是3。
3.指针的关系运算
两个指针之间也可以判断大小:
//演示2.3.1
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
while(p<arr+sz) //指针的⼤⼩⽐较
{
printf("%d ", *p);
p++;
}
return 0;
}
在while循环里,指针p从数组首元素的地址开始,依次自增,知道指向数组最后一个元素。
while循环的判断条件,就运用了指针大小的比较,这个点并不难理解。