从零开始的数据结构——C语言指针复习

从零开始的数据结构

由于笔者c语言没有学好,于是选择复习一遍指针,结构体,链表等,本期复习指针。

本篇文章提取改编自参考视频

参考视频 浙江大学翁恺老师c语言

指针复习

复习指针,看这一篇就够了。

一、基本概念与语法

指针就是保存地址的变量

int i;
int* p = &i;

此时我们说p指向了 i

上述代码也可以写成

int i;
int* p;
p = &i;

需要注意的是

int* p与int *p

表达含义相同

此时我们说 *p是一个 int (变量值)而 p 是一个指针


变量的值是内存的地址

普通变量的值是实际的值

指针变量的值是具有实际值的变量的地址

二、作为参数的指针

void f(int *p);

在被调用的时候得到了某个变量的地址,即要求传入一个指针

int i = 0;

f(&i);//通过&符号取得i的地址传入

在函数里面可以通过这个指针参数访问外界的 i 变量


#include<stdio.h>

void f(int *p);

int main(void)
{
    int i = 6;
    printf("&i=%p\n",&i);
    f(&i);
    g(i);
    
    return 0;
}

void f(int *p)
{
    printf("p=%p\n",p);
}

void g(int k)
{
    printf("k=%d\n",k);
}

&i与p的printf结果相等,为同一地址值

k的printf为6,与i相等

即p得到的是i的地址,k得到的是i的值

三、访问地址上的变量*

*是一个单目运算符,用来访问指针的值所表示的地址上的变量

void f(int *p)
{
    printf("p=%p\n",p);      //p是一个指针,指向地址,输出一个地址
    printf("*p=%d\n",*p);   //*p整体可以看成一个整形数,输出一个整形数
}

若在函数中修改*p,会影响到外部p所指向的变量,

四、指针常见错误

定义了指针变量,还未指向任何变量,就开始使用指针

即只声明未赋值

//下述为错误示范
int *p;
*p = 3;

这种方式是错误的,指针变量此时是一个野指针,任意指定了一个地址。

五、指针与数组

函数参数表中的数组实际上是指针

sizeof(a) == sizeof(int*)

可以用数组的运算符[]进行运算


以下四种函数原型等价(在参数表中出现等价):

int sum(int *ar,int n);
int sum(int *,int);
int sum(int ar[],int n);
int sum(int [],int);

数组变量本身表达地址

int a[10];//无需用&取地址

但是数组的单元表达的是变量,需要用&取地址

a == &a[0]

[]运算符可以对数组做,也可以对指针做

即,p[0]<==>a[0]

p[0]是把p所指的地方当作数组(当作只有一个长度的数组)


*运算符可以对指针做,也可以对数组做

*a=25

*a指向数组中的第一个元素


数组变量是const的指针,不能被赋值(指针常量)

int a[] <==> int *const a=…

六、指针与const

指针是const(指针常量)

表示一旦得到了某个变量的地址,不能再指向其他变量

int *const q = &i; //q 是const
*q = 26;           //可行
q++;               //不可行

数组是指针常量


所指是const(常量指针)

表示不能通过这个指针去修改那个变量(并没有使得那个变量本身成为const)

换言之,指针指向的变量的值不可通过该指针修改,但是指针指向的值可以改变。

const int *p = &i;
*p = 26;          //不对!(*p)是const
i =26;            //可行
p =&j;            //可行    

int i;
const int* p1 = &i;//O.o
int const* p2 = &i;//与O.o的形式一样
int *const p3 = &i;

判断哪个被constl的标志是const在*的前面还是在后面


const数组

const int a[]={1,2,3}

这样相当于在*前面加了一个const,表面数组的每个单元都素const int

必须通过初始化赋值,否则无法再改变了

保护数组值

因为把数组传入函数时传递的是地址,所以函数内部可以修改数组的值

为了保护数组不被函数破坏,可以设置参数为const

int sum(const int a[],int length)

七、指针运算

给一个指针+1表示要让指针指向下一个变量

int a[10];
int *p = a;
*(p+1)->a[1]//实际p+1的地址加了4(int类型)

如果指针不是指向一片连续分配的空间,则这种运算没有意义

指针值+1,实际地址+sizeof(那个基础类型)

#include<stdio.h>
int main(void)
{
    char ac[] = {0,1,2,3,4};
    char *p = ac;
    printf("p =%p\n",p);
    printf("p+1=%p\n",p+1);//输出的p+1和p的地址差1(char类型)
    int ai[] = {0,1,2,3,4};
    int *q = ai;
    printf("q =%p\n",q);
    printf("q+1=%p\n",q+1);//输出的q+1和q的地址差4(int类型)
    return 0;
}

指针能做的运算

加减一个整数(+,+=,-,-=)

递增递减(++/–)

两个指针相减,返回的是两个地址相减除以sizeof的差(即两个地址中间能放几个该类型的数)


*p++

取出p所指的那个数据来,然后再把p移到下一个位置去。

*的优先级虽然高,但是没有++高

常用于数组类的连续空间操作

在某些cpu上,这可以直接被翻译成一条汇编指令(可能跑得快)


指针比较

< , <= , == , > , >= , != 都可以对指针做

比较它们在内存中的地址

数组中的单元的地址是线性递增的


0地址(了解)

0地址通常是个不能随便碰的地址,你写的指针不应该有0值

因此可以用0地址来表示特殊的事情:

​ 返回指针无效;

​ 指针没有被真正初始化

NULL是一个预定定义的符号,表示0地址

有的编译器不愿意用0来表示0地址


指针类型

虽然无论什么类型的指针大小都一样,都是地址

但是指向不同类型的指针是不能互相赋值的,目的是为了避免用错指针

//下列为错误示范代码!!!
char ac[] = {0,1,2,3,4};
char *p = ac;
int ai[] = {0,1,2,3,4};
int *q = ai;
q = p;//会报错,因为指针类型不同

指针的类型转换

void*表示不知道指向什么东西的指针

计算时与char*相同(但不相通)

指针也可以转化类型

int *p = &i;
void *q = (void*)p;

这并没有改变p所指的变量的类型,而是改变看法,当作是个void

八、用指针做什么

需要传入较大的数据时

传入数组后对数组做操作

函数返回不止一个结果

需要用函数来修改不止一个变量

动态申请的内存

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值