目录
指针与字符串
函数返回多个值,某些值就只能通过指针返回 return只能返回一个值
传入的参数实际上是需要保存带回的结果的变量
求数组元素个数 sizeof(a) / sizeof(a0)
a是数组名
指针应用场景二 函数返回运算的状态,结果通过指针返回
让函数返回特殊的不属于有效范围内的值来表示出错
比如-1 或 0
但是当任何数值都是有效的可能结果时,就得分开返回了
错误:使用未指向任何变量的指针变量 解引用未初始化的指针
所有的本地变量都没有默认的初始值(随机
这可能不会出什么错,也可能会擦写数据或代码,或者导致程序崩溃
创建一个指针时,系统只分配了存储指针本身的内存,并未分配存储数据的内存。因此,在使用指针之前,必须先用已分配的地址初始化它。
double * pd;
* pd = 2.4; //不要这样做
未初始化的指针指向是不确定的
指针的字节是4
函数参数表里的数组实际上是指针 (所以参数表里可以写 int a[];
sizeof(a) == sizeof(int *)
(但是可以用数组的运算符[]进行运算
作为函数原型
数组变量本身表达地址,数组名前不需要取地址符,但是数组的单元表达的是变量
[]运算符可以对数组做,也可以对指针做
p[0] <==> a[0] //变址符嘛
*也可以对数组做
数组变量是const的指针,所以不能被赋值
即数组变量之间不能作互相赋值
int a[] <==> int * const a
(以下只适用于C99
指针是const
指针所指是const 表示不能通过指针去修改所指的值
比如p指向i i可以被赋值,p可以指向别的值,但是不能*p = ...
标志是const 与 * 的位置关系 (const 在 * 后则指针不可修改
int const*与int * const_冷崖的博客-CSDN博客_const int*和int*const
传结构
a 完全等价于 &a 么?
从类型来说,不的
它们不是 同类型 的指针
什么叫 同类型 的指针?
比如 char* 与 char* 是相同的 char 类型指针
比如 double* 与 double* 是相同的 double 类型指针
那么,不同类型 的指针,就是指
比如 double* 与 char*
比如 int* 与 float*
相同值 的指针,可以是 不同类型 的指针么?
char* p11 = a;
double*p12 = a;
int* p13 = a;
可以,编译器不禁止——可能会提醒一下——指针类型不匹配
(不过可以注意到,编译器只提醒p11,p12,不提醒p13)
如果是,替换为 同值 的&a
char* p21 = &a;
double*p22 = &a;
int* p23 = &a;
还是可以,编译器不禁止——可能会提醒一下——指针类型不匹配
(不过可以注意到,编译器提醒了p21,p22,p23)
上面的测试感觉到了什么意味?
是不是说
a 是 int* —— 即 int 类型指针
而 &a 不是 int* ?——虽然它们 值 相等
假定 a 与 &a 它们是 同类型 指针
那么 同类型 指针有什么特点呢?
比如,它们进行同样的加减法后,值 应该一样, 对吧
因为某类型指针 p 有如下的运算
p + n == p + n * sizeof(p的类型)
意思就是
如果有 a == &a 且 a 与 &a 是同类型的指针
那么
a + 1 == &a + 1 应该是成立的
a + 100 == &a + 100 应该是成立的
好比有
char* ch1 = "ABCDEFG";
char* ch2 = ch1;
int* ch3 = ch1;
那么 ch1 + 1 == ch2 + 1 应该是成立的
因为
ch1 == cha2
ch1 + 1 == ch1 + 1 * sizeof(char)
ch2 + 1 == ch2 + 1 * sizeof(char)
而 ch1 + 1 == ch3 + 1 就不能成立了
因为
ch1 == ch3
ch1 + 1 == ch1 + 1 * sizeof(char)
ch3 + 1 == ch3 + 1 * sizeof(int)
那么
a + 1 == &a + 1 是否成立?
a + 100 == &a + 100 是否成立?
……
很可惜,它们都不成立 //代码验证
说明 sizeof它们的指针指向的数据类型 是 不同 的值
即 a 与 &a 的 指针类型 是不同的
而且
很容易发现
a + n 是以 n * sizeof(int) 字节在移动指针
而
&a + n 是以 n * sizeof(int) * 10 字节在移动指针
其实
回到最开始,关于数组a的定义
int a[10];
含义是:
定义了一个 int [10] 类型的数组
数组的名字是 a
该数组未初始化
int [10]类型的数组意味着
数组的元素类型是 int,元素的数量是 10
a 是 数组 元素 类型 的指针 —— int* —— 它的移动单位是 sizeof(int) == 4 字节
&a 是 数组类型 的指针 —— int* [10] —— 它的移动单位是 sizeof(int [10]) == 4 * 10字节
可以定义
int* pt1 = a; https://没有编译警告
还可以定义
int (*pt2) [10] = &a; //没有编译警告,[]的运算级高于*,所以需要()
此时
a + 1 == pt1 + 1
&a + 1 == pt2 + 1
指针运算
sizeof(char) == 1
sizeof(int) == 4
*号是单目运算符,优先级比加减乘除高,需要加括号
没 有 意 义
因为如果是只移一个字节,则指针从这里开始指不能构成一片连续分配的空间
十六进制小心计算
两个指针相减得到的结果表示的是有几个单元格
即 两个地址的差 / sizeof(指向的类型)
*p++
取出p所指的数据之后把p移到下一个位置去
*的优先级没有++高
常用于数组类的连续空间操作
在某些CPU上,可以直接被翻译成一条汇编指令
指针乘除无意义
数组中的单元的地址肯定是线性递增的
0地址
Windows、Linux等操作系统(多进程)基本的管理单元叫进程
双击让其运行 就叫一个进程
对于进程,操作系统会给它一个虚拟的运行空间,所有的程序在运行的时候都以为自己有从零开始的一片连续的空间
内存中有0地址(任何一个程序),但是0地址通常是个不能随便碰的地址
所以指针不应该具有0值
因此可以用0地址来表示特殊情况: 1、返回的指针是无效的 2、指针没有被真正初始化(先初始化为0)
NULL是一个预定定义符号,表示0地址
有的编译器不愿意你用0来表示0地址,有点编译器0和NULL代表不同的含义
指针的类型
无论指向什么类型,所有指针的大小都是一样的,因为都是地址。
但是指向不同类型的指针是不能直接互相赋值的
这是为了避免用错指针
int *q = 0; 一个*q要四个字节
指针的类型转换
void* 表示不知道指向什么东西的指针
不确定它要指向什么,也不关心 表达有一块内存地址,往往用于底层程序,直接去访问某个内存地址或其代表的外部设备。
计算时与char*相同(但不相通)
指针也可以转换类型
int *p = &i ; void *q = (void*)p;
注意:并不会改变p所指的变量的类型
指针的运用
- 需要传入较大的数据时用作参数
- 传入数组后对数组做操作
- 函数返回不止一个结果
- 需要用函数来修改不止一个变量
动态内存分配
C99可以用变量做数组定义的大小
int *a = (int*)malloc(n*sizeof(int));
malloc() 在 stdlib.h 头文件中
malloc要的参数不是单元,而是空间,以字节为单位
注意malloc返回的是void* 记得类型转换
未初始化的指针只是不能解引用,还是可以赋值的
int *a = (int*) malloc(number*sizeof(int));
如果申请失败则返回0,或者叫NULL
while((p=malloc(100*1024*1024))
//用p得到的值作while的条件
p得到的地址如果不是0,则循环继续
free()只能还申请来的空间的首地址
报错:"pointer being freed was not allocated"
free(NULL); //√
free(0); //√
free(1); //×
常见问题:
- 申请了没free ——> 长时间运行内存逐渐下降
- free过了再free 程序会崩溃
- 地址变过了,直接去free(只能还首地址
malloc得到的空间是连续的吗?
内存不是无限的,所以malloc最终会失败,返回NULL指针,NULL的值为0,所以最后是写入地址0退出
字符串操作
putchar
int putchar(int c);
向标准输出写一个字符;
返回写了几个字符,EOF(-1)表示写失败
EOF(-1)是定义的一个宏,值为-1
getchar
int getchar(void)
从标准输入读入一个字符
返回类型是int是为了返回EOF(-1)
Windows Ctrl-Z
Unix Ctrl-D
没有输出EOF,说明只是强制让程序结束
得到了EOF的输出
在输入回车之前,这些字都还没有被送到程序,都还停留在shell处,直到你按下回车