简单理解指针

*&相互作用:*&a实际上就是a变量

  • 是C语言的优势,指针也就是地址

定义格式

类型 *指针变量名;类型* 指针变量名;

说明

  • 指针变量的类型是他指向内存单元中存放的数据类型
  • 指针变量必须被赋值语句赋值初始化后才能使用,否则,严重的话会死机
  • 可初始化为0NULL(不指向任何值)或者某个地址
  • 指针变量只能接受地址,赋以数据会错误

引用

  • 在指针引用前,要定义,赋值,否则,会造成系统混乱

指针运算符

取址符&

  • 单目运算符,结合性自左向右.

取内容符*

  • 也叫间接引用运算符,结合性自左向右,且*后面只能是指针.
  • 指针的值也可以改变,也就是改变指向.

指针的类型

  • 不同类型的指针不能相互赋值(虽然没问题)
1
2
3
int* a = NULL
char* b = NULL
a = b;

如果*a=0,则*b[0]-*b[3]都会变成0

  • 指针类型的转换

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

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

      • 并没有改变p所指的变量类型,而是用不同的眼光通过p去看它所指的变量
        • q此时认为p指向的变量不是int,而是void

场景1

利用函数交换数值(也就是说传给主函数多个数值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

void swap(int *pa, int *);

int main() {
int a, b;
a = 1;
b = 2;
swap(&a, &b);
printf("a=%d, b=%d", a, b);
return 0;
}

void swap(int *pa, int *pb){
int t;
printf("pa=%p,pb=%p\n", pa, pb);
printf("*pa=%d,*pb=%d\n", *pa, *pb);
t = *pa;
*pa = *pb;
*pb = t;
printf("pa=%p,pb=%p\n", pa, pb);
printf("*pa=%d,*pb=%d\n", *pa, *pb);
}

场景2

1.函数返回运算状态,指针返回结果

2.当要返回的值多个都是有效的结果时,要分开返回了

*p和p

  • *p是常量,p是变量

指针与数组

注意:函数参数表的数组其实就是指针

  • 以下四种函数原型是等价的
    • int sum(int *a, int b)
    • int sum(int*, int)
    • int sum(int a[], int b)
    • int sum(int [], int)

数组就是特殊的指针

  • []对指针和数组都可以用,同理*也一样

因为int a[]<==>int *const a=

所以这里不能被赋值

a = b;//error

一维数组指针

1
2
3
int a[10];
int *p;
*p = &a[0]

在C语言中规定数组名代表数组中的首地址(声明函数的参数不是,他不占实际内存单元)

实际上p=&a[0]p=a一样

  • 但是数组的单元表达的是变量,需要&取地址
    • 意思是把数组的首地址赋给p

p+1实际是p+1*dd代表字节数

综上,引用数组元素的方法有

  • 下标法:a[0]或p[0];
  • 指针法:*(a+i)或者*(p+i);

a是数组的首地址,即指针常量

  • 因为数组元素也是内存变量,所以此类指针的定义和使用指向变量的指针变量相同.
1
2
int a[10] *p;
p = a;
  • 此时p指向a[0],下面可以用p表示数组元素.
    • 下标表示:
1
p[0],p[1],...//需要定义指针数组
  • 指针表示法:
1
*(p+0),...
  • 注意:使用指针变量引用数据时,必须关注当前值
    • 比如:若p=p+3,则p[0]代表a[4]

二维数组指针

1
int  a[3][4];
  • a是首地址

  • 三个行元素的地址分别是:a,a+1,a+2a[0],a[1],a[2]也是地址量,即*(a+0),*(a+1),*(a+2)是一维数组的首个元素的地址

每个元素的地址&a[i][j],a[i]+j,*(a+i)+j都可以表示

元素的表示a[i][j],*(a[i]+j),*(*(a+i)+j)可以表示

要使用这两种方法引用元素的前提是二维数组全赋给指针数组

1
2
int  (*p)[3], a[2][3];
p = a;

注意:()不能去掉,因为[ ]的优先级高于()

  • 意思是一个指向二维数组的指针,只占int的字节数

type *p[num]的意思是一组指针,每个元素保存一个指针

  • 等价关系
    • a+i == p+i
    • a[i] == p[i] == *(a+i) == *(p+i)
    • a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)

说明:

  • ​ 赋给指针时首地址是a[0]**a表示a[0][0]

初始化的方法

方法一

1
2
char a[] = {0,1,3,4,5,6,7,8,9,-1};
char *pa = &a[0];

方法二

1
2
3
char a[] = {0,1,3,4,5,6,7,8,9,-1};
char *pa;
pa = &a[0];

错误表达

1
2
3
char a[] = {0,1,3,4,5,6,7,8,9,-1};
char *pa;
*pa = &a[0];//Error!

算术操作及比较

  • 只可以作加减法

    • p+n指的是p指向的数据单元之后的第n个数据单元

      • int *p;(设p的初始值是2000)

        p+1;表示2002

  • 指针值的比较(<,<=,>,>=,==,!=

    • 前提条件:p1p2是同一类型的指针变量,并且都指向同一段连续的储存空间

    • p1<p2为真的话结果是1,否则是0

  • 数组是递增排列的,a[0]>a[1]

CONST

1.只有C99以后的支持

1
int * const q = &a;
  • 此时q固定q++不能实现;
1
2
const int *q = &a;
int const* q = &a;
  • q可以被赋地址,但*q不能被赋值

2.非const转换为const

1
2
3
4
5
6
void f(const int* x);
int a = 15;
f(&a); //ok
const int b = a;
f(&b); //ok
b = a + 1; //error
  • 适用于传递的参数类型比地址大时

3.const数组

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

此时每个单元都是const

只能通过初始化赋值,

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

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

1
int sum(const int a[ ] );

0地址

  • 通常0地址不能乱碰

  • 你的指针不应该有0值

  • 0地址可以来表示特殊的事情

    • 返回的指针是无效的
    • 指针没有真正初始化
  • NULL是一个预定的符号,表示0地址

  • 一般用NULL表示0地址

作用

  • 传入较大的数据时用作参数

  • 传入数组后对数组进行操作

  • 返回多个结果

    • 修改多个变量
  • 动态申请内存

作者

manu

发布于

2019-11-03

更新于

2023-01-06

许可协议


:D 一言句子获取中...