数组:
有\0结尾的称为字符串 没有\0结尾的称为字符数组
字符数组strd 在算字符个数strlen时需要读到\0才算结束 但是在未定义大小的数组中初始化为字符时结尾是不给开辟\0存储空间的 所以结果不一定准确, -> 不要定义字符数组
int* ar[5]: (数组指针) 数组有五个元素构成 每个元素的类型是指针 是整型类型的指针 可以存放整型变量的地址
int(*pa)[5] (指针变量 存储数组的地址)是一个可以存放数组地址的指针 该数组开辟了五个空间或有五个元素的数组 每个元素是整型类型
int a = 1, b = 2, c = 3, d = 4;
int* ar[5] = {&a, &b, &c, &d};
指针: 四字节(与指针类型无关) 两个值 指针变量自身的值(存储的是地址) 指针变量所指的实体(解引用)
类型名与标识符中的*是 声明 int* ip
int* ip = &a;
*ip => a
&取地址
*解引用(钥匙)
值传递 传地址
实参给形参 结合 从右向左
野指针: 未初始化的指针 系统会给它赋一个随机值 (不一定指向哪里) 之后一旦给它赋值 会把其他区的值改变 危险!!
所以初始化时 要给未知指向的指针赋空 int* s = NULL;(空指针) -> 不能对空指针解引用、赋值.
定义指针时一定要初始化!!! 函数中形参如果是指针需要对其进行判空
int* fun(){ } // 返回值为 整型指针
只有编译链接成功后生成可执行文件才谈论生存期
不要将函数中的局部变量赋值给指针,函数结束后再通过该指针读取变量(eg.返回一个指针 该指针指向局部变量的地址) 因为函数结束后系统会将该栈帧回收再分配下一个函数使用,所以地址里面存放的值会相应的改变
数据区.data在程序结束后才还给系统 所以函数中可以定义静态变量(存放在.data) 指针指向静态变量的地址 就可以在函数外读取函数静态变量存放的值了
指针类型对指针变量的作用 1. 指针变量加一的能力(指针加一=>加sizeof(指针类型)) 2. 解析存储单元的大小
x = *p++; // 从右向左结合 将p取出与*结合 将其*p的值赋值给x 再将p进行+1
x = ++*p; // 从右向左结合 将p与*结合 取到p中存放地址对应的值 再++将其里面对应的值进行+1
指针的运算只有加减
*(解引用)和&(取地址)
int a = 10, b = 20; const int *p1 = &a; // 约束指向 约束* 所以不能改变*p1的值 // int const *p1 = &a; 等价 *p1 = 100; // error p1 = &b; | int a = 10, b = 20; int * const p2 = &a; // 约束自身 *没有被约束所以可以改变*p2 *p2 = 100; p2 = &b; // error |
int a = 10,b = 20; int* ip = &a; // ip 自由 *ip = 100; ip = &b; *ip = 200; | int a = 10, b = 20; const int * const p3 = &a; // 约束自身与指向 // int const * const p3 = &a; 等价 *p3 = 100; // error p3 = &b; // error |
指针有两个值 -> 自身&指向
const在*左边 是(指向)常性指针 不能通过解引用*p改变里面a的值,但是可以改变p的指向
const在*右边 是(自身)常性指针 不可以改变p的指向 可以通过*p改变指向对应的值
数组名 被看作该数组的第一个元素在内存中的首地址,但在sizeof中除外,sizeof(ar)是给出数组所占内存大小
ar[ i ] -> 编译成 *(ar + i) 下标方案编译成指针方案 i[ ar ] -> *(i + ar)也是可以的
当数组作为函数的形参是,数组名会退化成指针 ar[] -> *ar 所以形参也需要添加数组长度
多文件结构 #include #ifndef #endif
#include 本质是拷贝 有#的大情况都是在预编译时处理
头文件只参与预编译过程 在头文件内容被拷贝 .i 文件中
#include< > #include" "
使用尖括号< > 编译器会到系统路径下查找头文件
使用双引号" " 编译器首先在当前执行目录下查找头文件, 如果没有找到, 再到系统路径下查找
#ifndef A_H // A_H是否被定义过 没有的话进入
#define A_H
是否参与编译
#endif 防止头文件被重复引入
为了避免头文件被重复引入 也可以在.h中只写函数声明(加extern) 在同名.c/.cpp文件中写函数定义
fflush(stdin); // 清空缓冲区
rewind(stdin); // 将文件位置指示器移动到文件首位
断言assert
assert(br!=NULL); // 出错的话终止程序
定义函数: 函数名 功能描述 形参描述 返回值
看见指针一定要判空
函数 形参中有数组名 但函数中不要求对数组/字符串进行改变 可以在形参前加const 第一行需要放断言判空
字符串 <string.h>
字符串常量存放在数据区的只读区域
.c中可以用指针定义初始化字符串常量 char* str = "str";
.cpp中必须用常指针定义初始化字符串常量 const char* str = "abc";
字符串的长度是由" "定界,但是strlen 计算字符串长度 是遇到\0截止
char strb[30]; strb = "HELLO"; // 不能赋值成功的原因是strb代表数组首地址
strcpy(strb, "HELLO"); // 拷贝赋值
strdup 申请字符串副本 在堆区.heap申请空间 malloc free 原字符串存在于数据区是只读字符串,堆区的副本字符串可读可改 free(str); str = NULL; 释放str后指针str失效 要将失效指针置空
两个同类型指针,指向连续空间可以相减,相减后的结果是数据元素的大小
当且仅当两个同类型指针变量指向同一数组中的元素时,可以用关系运算符> == !=等进行比较,比较规则是指向后面元素的指针高,指向同一元素的相等
void* p; 无类型指针不能解引用