「C 语言」8 征服 C 指针

感谢你,编译器

指针类型(pointer type)

定义

指针类型可由函数类型、对象类型或不完全的类型派生,派生指针类型的类型称为引用类型

  • 先有指针类型
  • 所以有了指针类型的变量指针类型的值
  • 这里指针类型的值 几乎指的是内存的地址

操作符

  • 对变量使用取地址操作符& ,可以取得该变量的地址,这个地址称为指向该变量的指针 int *p=&a
  • 指针变量保存了指向其他变量的地址,可以说p指向了a
  • 对指针使用解引用操作符* ,就等同于它指向的变量,*p 等于 a

关于*的位置:靠近变量名

int *a, b VS int* a, b

指针运算

对于指针的加减运算,标准只允许 指针指向数组内的元素,或者超过数组长度的下一个元素

  • 对指针+1,地址的值会 增加当前指针所指向数据类型的长度

空指针

NULL——指向$\varnothing$

#define NULL 0 —— 0 在上下文中可以被识别为空指针

int *p = 0

#define NULL ((void*)0)

SWAP

void swap(int *a, int *b){
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

swap(&a, &b);

仅仅交换整形变量的值,可以不使用临时变量

#define SWAP(a, b) (a += b, b = a - b, a -= b)

!!!但是在SWAP(a[i], a[i]) 的情况下不可以

数组

在 C 中,如果在数组名后不加[],单独地只写数组名,那么此名称就表示「指向数组初始元素的指针」。

以上说法是错的

//p = &array[0];
p = array;
for (i = 0; i < 5; i++) {
    printf("%d\n", *(p + i));
}

*(p + i)p[i] 是等价的

所以不如

for (i = 0; i < 5; i++) {
    printf("%d\n", array[i]);
}
  • p[i]*(p + i)的简便写法。所以可以写成i[p]
  • 下标运算符[]原本只有这种用法,它和数组无关。

函数的参数传递

不要滥用指针运算

void strcpy(char *s, char *t)
{
    while ((*s++ = *t++)!='\0')
        ;
}

上面的while语句,前面的表达式——赋值语句返回左操作数

但是循环结束后,指针指向了空字符的下一个字符(容易引发bug)

不要修改传入的参数

数组作为函数参数

  • 如果试图将数组作为函数参数进行传递,那就传递指向初始元素的指针。

  • 无论如何都要将数组进行值传递的时候,建议将数组整体整理成结构体成员。

一般进行传址调用,在搜索时才会使用传值调用

声明函数形参的方法

int fn(int *a)int fn(int a[])

只有在声明函数形参时,数组的声明才可以被解读成指针(定义了元素个数是无用的)

int fn(int *a);
int fn(int a[]);
int fn(int a[10]);

内存地址

如今的操作系统会给每一个进程分配独立的「虚拟地址空间」

#C #笔记
0%