【笔记】C语言的指针

前言

C语言的指针学习笔记

定义一个指针

  • 在变量名前加*,表示指针变量
  • 指针类型与数据的类型要匹配
1
int *指针变量名;

为指针赋值

  • 把变量的内存地址存储在指针

  • 在变量名前加&,表示变量的内存地址

    • 对于寄存器变量而言,寄存器变量是存放在CPU里面的,而不是内存,所以没有地址值,所以不可以使用&获取地址值
  • 什么类型的指针指向什么类型的数据,如果使用了不同类型,会出现不兼容的情况

    • void *指针变量名可以指向任何类型的值
1
2
3
4
int 变量名 = 0;
int *指针变量名;

指针变量名 = &变量名;
  • *指针变量名:表示指针变量指向的值
  • 指针变量名:表示指针存储的地址值

输出指针的数据

输出地址

1
printf("%p", 指针变量名);

输出指向的值

1
printf("%d", *指针变量名);

指针占用的大小

  • 不论是存储什么类型数据的指针,其占用的内存大小都是一样的

野指针

  • 没有初始化过值的指针,这种指针叫野指针
  • 程序中不要出现野指针
1
int *p;

空指针

  • 如果一个指针变量没有明确的指向一块内存,那么就把这个变量指向NULL
1
int *p = NULL;

NULL

  • NULL在C语言是一个宏常量,其值为0
1
#define NULL 0

指针常量和指向常量的指针

指向常量的指针

  • 指向常量的指针指的是指针所指向的数据是一个常量

  • 指针p可以指向一个类型的地址,但不可以用*p的方式修改这个内存的值

  • 常量不可以被修改,但是可以通过指针变量修改常量的值,此时编译源码会有警告

  • 这是C语言的一个漏洞,但是在C++中没有这个漏洞

1
2
3
4
5
6
7
int a = 0;
a = 1;

const int *p = &a;
// *p = 1;

printf("%d\n", *p);
1
2
3
4
5
6
7
const int a = 0;
// a = 1;

int *p = &a;
*p = 1;

printf("%d\n", *p);

防止警告

  • 为了防止警告,可以强制类型转换
1
2
3
4
5
6
7
const int a = 0;
// a = 1;

int *p = (int *)&a;
*p = 1;

printf("%d\n", *p);

C语言的常量

  • 因为有这样的漏洞,所以相比于使用const定义常量,最好使用#define来定义常量

指针常量

  • 常量指针指的是指针存储的内存地址是常量

  • p只能指向a的地址,并且不能改变

1
2
3
4
5
int a;
int b;

int *count p = &a;
// p = &b;

指向数组

  • 当指针变量指向数组的时候,C语言语法规定指针变量名可以当数组名使用
1
2
3
4
5
6
7
8
int *p;
int a[1] = { 0 };

// 数组赋值给指针
p = a;

// 通过指针直接对数组操作
p[0] = 1;

指针运算

  • 指针变量可以计算
  • 例如:如果是int *类型的指针+1,那么增加4个整数位

指针数组

1
int *指针变量名[1];
  • 指针数组名不能作为变量接收值

定义一组空指针

1
int *指针变量名[1] = { NULL }

为指针数组赋值

1
2
3
int *指针变量名[1];
int 变量名;
指针变量名[0] = &变量名;

二级指针

  • 指向指针变量的指针
1
2
3
4
5
6
int a;
int *b;
int **c;

b = &a
c = &b
  • c的值是*b的地址
  • *c的值是b的值,也就是a的地址
  • **c的值是a的值

多级指针

  • 多个层级的指针
  • 能用少的层级即决问题的程序,不要使用多级指针

指针作为形参

数组作为形参

1
2
3
4
5
6
7
8
9
10
void fun(int *a)
{
...
}

int main()
{
int a[1];
fun(a);
}
  • 如果一个数组作为函数的参数,那么数组的成员数量在函数内部是不可见的
  • 在传递一个数组时,同时提供另外一个参数,标明这个数组有几个成员变量

main函数的形参

argc:指针数组的长度,代表参数的数量
**args:指针数组,代表命令行的参数

1
2
3
4
int main(int argc, char **args)
{
...
}

不修改实参内部的值

1
2
3
4
5
6
7
8
9
10
void fun(const int *a)
{
...
}

int main()
{
int a[1];
fun(a);
}

指针作为返回值

1
2
3
4
int *fun()
{
...
}

memset 函数

  • 实现内存设置
  • 将指定位置的内存置为空值

引入头文件

1
#include <string.h>

<point>:指定要置空内存的首地址,如果是数组可以指定数组名
0:表示置空
sizeof(<point>):这块内存的大小

1
memset(<point>, 0, sizeof(<point>));

memcpy 函数

  • 实现同类型数据的内存复制

arrFull:有数据的数组
arrNull:没有数据的数组,需要被复制
size(arrNull):赋值的内存大小

1
2
3
4
int arrFull[3] = {1, 2, 3};
int arrNull[3] = { 0 };

memcpy(arrNull, arrFull, sizeof(arrNull));

memmove 函数

  • 实现内存移动
1
2
3
4
int arrFull[3] = {1, 2, 3};
int arrNull[3] = { 0 };

memmov(arrNull, arrFull, sizeof(arrNull));

完成