c:指针(2)

1. 指针运算

1.1 算术运算

  • 加减+、-
    指针与整数相加:表示指针指向下个变量。
    指针与整数相减:表示指针指向上个变量。
    指针与指针相减:两个指针的元素间隔个数。
int arr[]={100,101,102,103,104,105};
int* p = arr;
int* q;
for(int i=0;i<5;++i){
    q = p+i;
    printf("%d\n",*q);
}
for(int i=0;i<5;++i){
    p = q-i;
    printf("%d\n",*p);
}
printf("q-p=%d\n",q-p);
  • 自增自减++、- -
    指针能够算术运算,必然能够自增自减。
int arr[]={100,101,102,103,104,105};
int* p = arr;
for(int i=0;i<5;++i){
    printf("%d\n",*p++);
}
for(int i=0;i<5;++i){
    printf("%d\n",*p--);
}

操作说明

1.操作数是指针
2.自增自减++、- -优先级高于解引用*

计算过程

1.运算++/- -,返回的是p的值(地址),然后p自加/自减。
2.运算*,获取p指向的值。
等价于

*p;
p=p+1;
自增自减相当于
*q++*(q++)
*q- -*(q- -)

操作说明

操作数是指针
1.前缀自增自减++、- -和解引用*的结合律是自右向左。
2.前缀自增自减++、- -在解引用*的右边,优先计算。

计算过程

1.运算++/–,p自加/自减,返回的是p自加/自减后的值(地址)。
2.运算*,获取p指向的值。

自增自减相当于
*++q*(++q)
*- -q*(- -q)

操作说明

*操作数是指针,前缀自增自减++、- -操作数是指针指向的值。
前缀自增自减++、- -和解引用*的结合律是自右向左。
解引用*在前缀自增自减++、- -的右边,优先计算。
计算过程

运算*,获取p指向的值。
运算++/- -,p指向的值自加/自减。

自增自减相当于
++*q++(*q)
- -*q- -(*q)

如果一个表达式里有多个运算符,则先进行优先级比较,先执行优先级高的运算符;如果优先级相同,那就看结合性,根据结合方向来做运算。

1.2 单位长度

int iarr[] = {1,2,3,4,5,6};
int* p = iarr;
for(int i=0;i<5;++i){
    printf("%p\n",p++);
}

char carr[] = {1,2,3,4,5,6};
char* q=carr;
for(int i=0;i<5;++i){
    printf("%p\n",p++);
}
  • 应用范围
    指针的算术运算表示在一片连续空间上的移动。
    指针的比较运算也是用于一片连续空间的地址比较。
    常用于数组等连续内存。

2. 指针类型

1.无论指向什么类型,所有指针的大小都是一样的,都是地址的大小。

char* str;
short* ps;
int* pn;
long* pl;
long long* pll;
float* pf;
double* pd;
long double* pld;

2.指针类型转换
指向不同类型的指针不能直接相互赋值(特例void*),需要强制类型转换。

char* str = "abcd";
int* p = str;

指针类型转换没有改变指针内的地址,也没有改变指针指向的值,只是改变了移动的单位长度。

#include <stdio.h>
int main(){
    char* str = "abcdef";
    int* p=(int*)str;
    p++;
    char* q = (char*)p;
    printf("%c\n",*q);
}

3.void类型的指针
void*是一种很特别的指针,表示指向未知类型的指针,并不指定它是指向哪一种类型的数据,而是根据需要转换为所需数据类型。

int n = 0;
int* p = &n;
void* q = p;
int* k = (int*) q;

指针作用小结
1.较大数据结构体传入时做参数。
2.传入数组后,对数组做操作。
3.函数需要多个返回值时,作为返回值参数。
4.动态申请内存。
5.避免使用未初始化指针、空指针和野指针。

3. 数组指针 vs 指针数组

3.1 数组指针

指向一个数组指针称为数组指针。

int n = 0;
int* p = &n;
int arr[] = {1,2,3,4,5,6};
int* q = arr;

3.2 指针数组

指针是一个类型,也可以组成一个数组,这样的数组称为指针数组。

#include <stdio.h>

int main(){
    int a = 1;
    int b = 2;
    int c = 3;
    int* p[] = {&a,&b,&c};
    for(int i=0;i<3;++i){
        printf("%d\n",*p[i]);
    }
    for(int i=0;i<3;++i){
        printf("%d\n",**(p+i));
    }
}

[]的优先级高于*,那么p先和[]结合,说明这是一个数组。再和int*结合,说明这个数组里的每个元素都是一个指针,每个元素都能保存一个地址。

4. 常量指针 vs 指针常量

4.1 常量指针const int* p

可以写作int const *ppint*类型,const修饰的是*p,所以*p是常量,表示p指向的地址里的值不可修改,也就是说,p里的值不能再重新赋值了,但是可以修改p指向的地址。

int a = 10;
int b = 20;
const int *p = &a;
p = &b;      // 可以
*p = 100;    // 错误

4.2 指针常量int* const p

pint*类型,那么const修饰的是p,所以p是常量,表示p指向的地址不可修改,即p不能再指向别的地方了,但是可以修改p指向的这个地址里的值。

int a = 10;
int b = 20;
int * const p = &a;
p = &b;      // 错误
*p = 100;    // 允许

4.3 常量指针常量const int* const p

p是int类型,两个const分别修饰了p和p, 所以p和*p都是常量,表示p指向的地址不可修改,同时p指向的地址里的值也不可修改。

int a = 10;
int b = 20;
const int *const p = &a;
p = &b;       // 错误
*p = 100;     // 错误

自由的代价,是永远的警惕。-- C Primer Plus
你定义了一个指针,那就一定要知道这个指针指向的什么地方,而且你要保证这个指针是真实有效的,否则我就用程序崩溃来惩罚你。

NO.例子名称指向的值地址
1const int* p/int const* p常量指针不可改变可改变
2int* const p指针常量可改变不可改变
3const int* const p常量指针常量不可改变不可改变

*之前的const修饰指向的变量,*之后的const修饰指针。

0地址

#include <stdio.h>

int main(){
    int *p = 0;
    printf("%d\n",*p);
}

0地址是内存中不能访问的地址。在C语言中,标准库定义NULL表示0地址。
通常用来表示如下:

1.指针没有初始化
2.返回指针无效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值