04. 数组与函数
定义数组
1 | int arr[100]; // 此时还没有初始化 |
数组的特点
- 所有的元素具有相同的类型
- 一旦创建, 不能改变大小。
- 数组中的元素在内存中是连续依次排列的。
二维数组
可以理解为数组的数组, 数组的每个元素仍然是一个数组.
遍历用两重循环
数组的长度
sizeof 给出整个数组占据的内容大小, 单位是字节.
size(a) / size(a[0]) // 占据大小 / 单个元素的大小, 相除就得到了数组的单元个数
注意: 数组作为函数参数时, 往往还需再传一个参数来表示数组的长度
函数
函数: 是一块代码, 做一件事.
函数的先后关系:

函数原型
函数头, 已分号结尾就构成了函数原型。
函数原型的目的告诉这个函数长什么样。
- 名称
- 参数(数量及类型)
- 返回类型

建议函数原型声明的时候写全, 例如这样
void swap(void),而非void swap(), 否则会引起编译器的误解.
本地变量:
函数的每次运行, 产生一个独立的变量空间,在这个空间中的变量, 是函数的这次运行所独有的,称作本地变量.
05. 指针
取址运算符 &
- scanf(“%d”, &i)里面的 &
- 获得变量的地址后, 它的操作数必须是变量
- int i; printf(“%x”, &i) //16进制输出
- 地址的大小是否与 int 相同类型
sizeof(int)取决于编译器- int i; printf(“%p”, &i);
1 | // 无符号浮点型 |
- 变量的值是内存的地址。
- 普通变量的值是实际的地址。
- 指针变量的值是具有实际值的变量的地址。
错误写法
1 | int i; |
指针
它的值是变量的地址.
int *p, q; // 表示p是一个int型指针变量, q是普通int型.
数组变量是特殊的指针
函数参数表中的数组实际上就是指针
所以以下四种函数原型是等价的
- int sum(int *arr, int n);
- int sum(int *, int);
- int sum(int arr[], int n);
- int sum(int [], int n);
1 | int a[] = {5, 15, 34, 54, 14, 2, 52, 72}; |
练习
/*
GPS数据处理
题目内容:
NMEA-0183 协议是为了在不同的 GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA-The National Marine Electronics Associa-tion)制定的一套通讯协议。GPS接收机根据NMEA-0183协议的标准规范,将位置、速度等信息通过串口传送到PC机、PDA等设备。
NMEA-0183 协议是 GPS 接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接收机、GPS数据处理软件、导航软件都遵守或者至少兼容这个协议。
NMEA-0183 协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有GPGGA、GPGSA、GPGSV、GPRMC、GPVTG、GPGLL 等。
其中$GPRMC语句的格式如下: $GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,A*50
这里整条语句是一个文本行,行中以逗号“,”隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。
字段0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
字段1:UTC时间,hhmmss.sss格式
字段2:状态,A=定位,V=未定位
字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段4:纬度N(北纬)或S(南纬)
字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段6:经度E(东经)或W(西经)
字段7:速度,节,Knots
字段8:方位角,度
字段9:UTC日期,DDMMYY格式
字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
字段11:磁偏角方向,E=东W=西
字段16:校验值
这里,“”为校验和识别符,其后面的两位数为校验和,代表了“$”和“”之间所有字符(不包括这两个字符)的异或值的十六进制值。上面这条例句的校验和是十六进制的50,也就是十进制的80。
提示:^ 运算符的作用是异或。将 $和之间所有的字符做^运算(第一个字符和第二个字符异或,结果再和第三个字符异或,依此类推)之后的值对65536取余后的结果,应该和后面的两个十六进制数字的值相等,否则的话说明这条语句在传输中发生了错误。注意这个十六进制值中是会出现A-F的大写字母的。
现在,你的程序要读入一系列 GPS 输出,其中包含 $GPRMC,也包含其他语句。在数据的最后,有一行单独的
END
表示数据的结束。
你的程序要从中找出 GPRMC语句,计算校验和,找出其中校验正确,并且字段2表示已定位的语句,从中计算出时间,换算成北京时间。一次数据中会包含多条GPRMC语句,以最后一条语句得到的北京时间作为结果输出。
你的程序一定会读到一条有效的 $GPRMC 语句。
输入格式:
多条 GPS 语句,每条均以回车换行结束。最后一行是END三个大写字母。
输出格式:
6位数时间,表达为:
hh:mm:ss
其中,hh是两位数的小时,不足两位时前面补0;mm是两位数的分钟,不足两位时前面补0;ss是两位数的秒,不足两位时前面补0。
输入样例:
$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,A*50
END
输出样例:
10:48:13
*/
1 | #include<stdio.h> |
06. 字符串
char 是一种整数, 也是一种特殊的类型: 字符
- 用单引号表示的是字符的字面量: ‘a’, ‘1’
- ‘’ 也是一个字符
- printf 和 scanf 里用%c来输入输出字符。
大小写转换
- 字母在 ASCII 表中是顺序排列的。
- 大写字母和小写字母是分开排列的,并不在一起。
- ‘a’ - ‘A’ 可以得到两段之间的距离,于是,
a + 'a' - 'A'可以把一个大写字母变成小写字母。a + 'A' - 'a'可以把一个小写字母变成大写字母。
C语言的字符串是以字符数组的形态存在的
- 不能用运算符对字符串做运算
- 通过数组的方式可以遍历字符串
字符串(其实还是一个字符数组, 但是以’\0’结尾)

- 0 标志字符串的结束, 但它不是字符串的一部分
- 字符串以数组的形式存在, 以数组或指针的形式访问.
用指针还是数组
- char* str = “Hello”;
- char str[] = “Hello”;
用数组: 当这个字符串在这里, 作为了本地变量控件会被自动回收
用指针: 当这个字符串不知道在哪里, 用于只读, 用于处理参数 和 动态分配空间
看上去明显用指针更通用。
总而言之如果要构造字符串用数组, 否则用指针。
#include<string.h>的一些方法

strlen 返回 s 的字符串长度(不包含结尾的 0)
int strcmp(const char *s1, const char * s2) 比较两个字符串, 返回:

int putchar(int c)
向标准输出写一个字符
返回写了几个字符, EOF(-1)表示写失败
getchar
从标准输入读入一个字符
返回类型是 int, 是为了返回 EOF(-1)
- windows–> Ctrl + Z
- Unix–> Ctrl + D
1 | int main(int argc, char const *argv[]) { |
标准 ASCII 编码表
ASCII 码(十进制)控制字符 ASCII 码(十进制) 控制字符
0 NUT 32 (space)
1 SOH 33 !
2 STX 34 ”
3 ETX 35 #
4 EOT 36 $
5 ENQ 37 %
6 ACK 38 &
7 BEL 39 ’
8 BS 40 (
9 HT 41 )
10 LF 42 *
11 VT 43 +
12 FF 44 ,
13 CR 45 -
14 SO 46 .
15 SI 47 /
16 DLE 48 0
17 DCI 49 1
18 DC2 50 2
19 DC3 51 3
20 DC4 52 4
21 NAK 53 5
22 SYN 54 6
23 TB 55 7
24 CAN 56 8
25 EM 57 9
26 SUB 58 :
27 ESC 59 ;
28 FS 60 <
29 GS 61 =
30 RS 62 >
31 US 63 ?
64 @ 96 `
65 A 97 a
66 B 98 b
67 C 99 c
68 D 100 d
69 E 101 e
70 F 102 f
71 G 103 g
72 H 104 h
73 I 105 i
74 J 106 j
75 K 107 k
76 L 108 l
77 M 109 m
78 N 110 n
79 O 111 o
80 P 112 p
81 Q 113 q
82 R 114 r
83 S 115 s
84 T 116 t
85 U 117 u
86 V 118 v
87 W 119 w
88 X 120 x
89 Y 121 y
90 Z 122 z
91 [ 123 {
92 \ 124 |
93 ] 125 }
94 ^ 126 ~
95 _ 127 DEL
特殊控制字符说明
NUL 空
VT 垂直制表
SYN 空转同步
SOH 标题开始
FF 走纸控制
ETB 信息组传送结束
STX 正文开始
CR 回车
CAN 作废
ETX 正文结束
SO 移位输出
EM 纸尽
EOY 传输结束
SI 移位输入
SUB 换置
ENQ 询问字符
DLE 空格
ESC 换码
ACK 承认
DC1 设备控制 1
FS 文字分隔符
BEL 报警
DC2 设备控制 2
GS 组分隔符
BS 退一格
DC3 设备控制 3
RS 记录分隔符
HT 横向列表
DC4 设备控制 4
US 单元分隔符
LF 换行
NAK 否定
DEL 删除
字符串中存在 ASCLL 为 160 的空格,并且该空格不能通过 input.replaceAll("\\s+", " ");
以及 trim 的方法去除。
需要通过下面的代码可以去除 replaceAll("[\\u00A0]+", "")
07. 指针的使用
应用场景
- 函数返回的运算状态, 结果通过指针返回
- 常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错 -1 或者 0
- 后续的语言(C++, Java)采用了异常机制来解决这个问题
指针是 const
- 表示一旦得到某个变量的地址, 不能再指向其他变量 指针不可被修改, const 指针
1 | int * const q = &i; // q 是const |
所指的是 const
- 表示不能通过这个指针修改那个变量(并不能使得那个变量成为 const) 指针指向的东西不可修改
1 | const int * q = &i; // q 是const |
putchar
- int puchar(int c);
- 向标准输出写一个字符