文章目录
C语言
C简介
C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的。C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现。
在 1978 年,布莱恩·柯林汉(Brian Kernighan)和丹尼斯·里奇(Dennis Ritchie)制作了 C 的第一个公开可用的描述,现在被称为 K&R 标准。
UNIX 操作系统,C编译器,和几乎所有的 UNIX 应用程序都是用 C 语言编写的。由于各种原因,C 语言现在已经成为一种广泛使用的专业语言。
C基本语法
Token
分号
注释
标识符
关键字
常量
常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量 。
常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。
常量就像是常规的变量,只不过常量的值在定义后不能进行修改。
整数常量
0x:十六进制
0:八进制
不带前缀默认十进制,整数常量可以带后缀,后缀是U/L,U表示无符号整数,L表示长整数。
浮点常量
浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。
带符号的指数是用 e 或 E 引入的。
字符常量
字符常量是括在单引号中,例如,‘x’ 可以存储在 char 类型的简单变量中。
字符常量可以是一个普通的字符(例如 ‘x’)、一个转义序列(例如 ‘\t’),或一个通用的字符(例如 ‘\u02C0’)。
在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。
转义序列 | 含义 |
---|---|
\ | \ 字符 |
’ | ’ 字符 |
" | " 字符 |
? | ? 字符 |
\a | 警报铃声 |
\b | 退格键 |
\f | 换页符 |
\n | 换行符 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ooo | 一到三位的八进制数 |
\xhh . . . | 一个或多个数字的十六进制数 |
字符串常量
字符串字面值或常量是括在双引号 “” 中的。
定义常量
在 C 中,有两种简单的定义常量的方式:
- 使用 #define 预处理器。
- 使用 const 关键字。
#define 预处理器
下面是使用 #define 预处理器定义常量的形式:
#define identifier value
const 关键字
您可以使用 const 前缀声明指定类型的常量,如下所示:
const type variable = value;
变量
变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C 是大小写敏感的。几种基本的变量类型:
- char:一个Byte,整数类型
- int:整型,4个Byte,取值范围 -2147483648 到 2147483647。
- float:单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。
- double:双精度浮点值。双精度是1位符号,11位指数,52位小数
- void:表示类型的缺失。
C中变量定义
type variable_list;或type variable_name = value;
数据类型
- 基本类型
- 整数
- short int
- int
- long int
- long long int
- 浮点
- float
- double
- Long double
- 字符
- Char
- 布尔
- _Bool
- 枚举
- enum
- 整数
sizeof运算符:用于获得数据类型或表达式长度
signed:变量带符号位
unsigned:变量不带符号位
取值范围
比特位,CPU能读取的最小寻址单位
1Byte=8bit
4Byte表示十进制范围,-65534~65535
二进制表示负数使用补码形式
1.先取得该数的绝对值的二进制形式
2.再将第1步的值按位取反
3.最后将第2步的值加1
字符和字符串
赋值运算符
=,lvalue,rvalue
算数运算符
+,-,*,/,%,+(正号),-(负号)
逻辑运算符
与:&&
或:||
非:!
短路求值,只有当第一部分运算无法确定返回结果的真假时才计算后面的表达式
if语句
if(表达式){
......//执行语句
}
else if{
....../执行语句
}
else{
....../执行语句
}
switch语句
switch(表达式){
case expression1:语句1;
break;
case expression2:语句2;
break;
...
case expressionn:语句n;
break;
default:默认语句;
break;//可写可不写
}
分支结构的嵌套
- 根据流程图写代码
while语句
do-while语句
循环的基本结构
- 初始化计数器
- 循环条件
- 更新计数器
for语句
for(表达式1;表达式2;表达式3)
{
......//执行语句
}
break语句和continue语句
break:中断循环
continue:跳过满足条件的某次循环
数组
-
数组的定义
-
数组的初始化
字符数组
- 字符串常量
- 字符数组:
- 指定固定长度数组,然后赋值
- 在定义的时候直接初始化数组
字符串处理函数
- 获取字符串长度函数strlen
- 拷贝字符串strcpy和strncpy,要保证目标字符串长度足以容纳要拷贝过来的字符串,注意strcpy拷贝字符串最后给自动添加结束符,strncpy的拷贝字符串最后默认没有自动添加结束符需要手动加上,不然会有乱码被复制
- 连接字符串:strcat和strncat
- 比较字符串:strcmp和strncmp
二维数组
- 类型 数组名[常量表达式][常量表达式]
- int a[6][6]6行6列
指针
- 指针:内存地址,指针变量用来存放内存地址的变量。就像其他变量或常量一样,在使用指针存储其他变量地址之前对其进行声明。
- 指针变量
- 定义:type *var_name;
- type是指针类型,必须为有效的C数据类型,var_name是指针变量的名称。
- char *pa = &a;//
- 定义:type *var_name;
指针和数组
-
用一个指针指向数组,把指针地址指向数组的第一个元素地址
-
char *p p = a;//语句1 p = &a[0];//语句2
-
-
指针的运算:当指针指向数组元素的时候,我们可以对指针变量进行加减运算,这样做的意义相当于指向距离指针所在位置向前或向后第n个元素。
-
对比标准的下标法访问数组元素,这种使用指针进行间接访问的方法叫做指针法
-
需要郑重强调的是:p+1并不是简单的将地址加1,而是指向数组的下一个元素。
指针数组和数组指针
指针数组
- 定义:是一个数组,每个数组元素存放一个指针变量
Int *p1[5];
#include <stdio.h>
int main()
{
char *p1[5]={
"让编程改变世界",
"just do it","一切皆有可能","永不止步","one more thing"
};
int i;
for (i=0;i<5;i++){
printf("%s\n",p1[i]);
}
return 0;
}
#include <stdio.h>
const int MAX = 3;
int main(){
int var[3]={10,100,200};
int i,*ptr[MAX];
for (i=0;i<MAX;i++){
ptr[i]=&var[i];
};
for (i=0;i<MAX;i++){
printf("var[%d]=%d\n",i,*ptr[i]);
printf("ptr[%d]的地址:%p\n",i,ptr[i]);
}
return 0;
}
数组指针
- 定义:一个指向数组的指针
int (*p2)[5]
#include<stdio.h>
int main()
{
int temp[5]={1,2,3,4,5};
int (*p1)[5]=&temp;
int i;
for (i=0;i<5;i++){
printf("%d\n",*(*p1+i));
};
return 0;
}
指针和二维数组
解引用:把一个地址的值取出来叫解引用
语法糖:
指针计算:*(array+i)==array[i]
void指针和null指针
-
void指针:通用指针,可以支持不同类型指针之间的互相转换
-
#include <stdio.h> int main(){ int num = 1024; int *pi = # char *ps = "FishC"; void *pv; pv = pi; printf("pi:%p,pv:%p\n",pi,pv); printf("pv:%d\n",*(int *)pv); pv=ps; printf("ps:%p,pv:%p\n",ps,pv); printf("pv:%s\n",(char *)pv); return 0; }
-
null指针:不指向任何数据
-
NULL用于指针和对象,表示控制,指向一个不被使用的地址;而‘\0‘表示字符串的结尾。
-
#include <stdio.h> int main() { int *ptr = NULL; printf("null指针地址:%p\n",ptr ); return 0; }
-
指针的算数运算
C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、–、+、-。
假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:
ptr++
在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。
我们概括一下:
- 指针的每一次递增,它其实会指向下一个元素的存储单元。
- 指针的每一次递减,它都会指向前一个元素的存储单元。
- 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。
递增指针
#include <stdio.h>
const int MAX=3;
int main()
{
int var[]={10,100,200};
int i,*ptr;
ptr=var;
for (i=0;i<MAX;i++){
printf("存储地址:var[%d]=%p\n",i,ptr);
printf("存储值:var[%d]=%d\n",i,*ptr);
ptr++;
}
return 0;
}
递减指针
#include <stdio.h>
const int MAX=3;
int main()
{
int var[]={10,100,200};
int i,*ptr;
ptr=&var[MAX-1];
for (i=MAX;i>0;i--){
printf("存储地址:var[%d]=%p\n",i-1,ptr);
printf("存储值:var[%d]=%d\n",i-1,*ptr);
ptr--;
}
return 0;
}
指针的比较
#include <stdio.h>
const int MAX=3;
int main()
{
int var[]={10,100,200};
int i=0,*ptr;
ptr=&var[0];
while(ptr<=&var[MAX-1]){
printf("存储地址:var[%d]=%p\n",i,ptr);
printf("存储值:var[%d]=%d\n",i,*ptr);
ptr++;
i++;
}
return 0;
}
指向指针的指针
#include <stdio.h>
int main()
{
int V;
int *p1;
int **p2;
V = 100;
p1 = &V;
p2 = &p1;
printf("var=%d\n",V);
printf("p1=%p\n",p1);
printf("*p1=%d\n",*p1);
printf("p2=%p\n",p2);
printf("**p2=%d\n",**p2);
return 0;
}
指针传递给函数
C 语言允许传递指针给函数,只需要简单地声明函数参数为指针类型即可。
#include <stdio.h>
void getSeconds(unsigned long *par);
int main()
{
unsigned long sec;
getSeconds(&sec);
printf("Number of seconds:%ld\n",sec );
return 0;
}
void getSeconds(unsigned long *par)
{
*par = time(NULL);
return;
}
附录 查询文档
printf格式化输出函数
#include <stdio.h>
...
int printf ( const char * format, ... );
参数解析:
1、format 参数
format 参数是一个格式化字符串,由格式化占位符和普通字符组成。
格式化占位符(以 % 开头)用于指明输出的参数值如何格式化。
格式化占位符的语法如下:
%/[flags]/[width]/[.precision]/[length]specifier
每一个格式化占位符均以 % 开始,以转换字符结束。
specifier**(转换字符,必选)的内容及含义如下:**
转换字符 | 参数类型;转换结果 |
---|---|
c | char;字符 |
d | int;有符号十进制整数 |
i | 同上 |
e | double;以指数形式输出单、双精度浮点数(小写 e) |
E | 同上(大写 E) |
f | double;以小数形式输出单、双精度浮点数 |
g | double;以 %f 或 %e 中较短的输出宽度输出单、双精度浮点数(指数显示小写 e) |
G | 同上(指数显示大写 E) |
o | unsigned int;无符号八进制(无前导 0) |
s | char *;字符串 |
u | int;无符号十进制 |
x | unsigned int;无符号十六进制(无前导 0x) |
X | 同上(无前导 0X) |
p | void *;指针值 |
n | int *;存放已写字符的个数 |
% | 不进行参数转换;% 自身 |
注:如果 % 后边的字符不是转换字符,则其行为没有定义。
flags**(标志,可选)的内容即含义如下:**
标志 | 含义 |
---|---|
- | 指定被转换的参数在其字段内左对齐(默认是右对齐) |
+ | 指定在输出的数前面加上正负号 |
空格 | 如果第一个字符不是正负号,则在其前面加上一个空格 |
0 | 对于数值转换,当输出长度小于字段宽度时,添加前导 0 进行填充 |
# | 指定另一种输出形式: 1. 如果转换字符为 o,则第一个数字为 0 2. 如果转换字符为 x 或 X,则指定在输出的非 0 值前加 0x 或 0X 3. 对于转换字符为 e、E、f、g 或 G 的情况,指定输出总是包含一个小数点。另外,对于转换字符为 g 或 G,还指定输出值尾部无意义的 0 将被保留 |
注:flags 可同时出现多个,且无顺序要求。
width(宽度,可选)是一个数值,用于指定最小字段的宽度
转换后的参数输出宽度至少要达到这个数值。如果参数的字符数小于该数值,则在参数左边(如果 flags 设置为 -,要求左对齐的话则在右边)填充一些字符。填充字符通常为空格,但是如果 flags 设置为 0,则填充字符为数字 0。
.precision(.精度,可选),通过点号(.)分隔字段的宽度和精度
- 对于字符串,它指定打印的字符的最大个数
- 对于整数,它指定打印的数字位数(必要时可加填充位 0 以达到宽度要求)
- 对于转换字符为 e、E 或 f,它指定打印的小数点后的数字位数
- 对于转换字符为 g 或 G,它指定打印的有效数字位数
length(长度修饰符,可选)的值可以是 h、hh、l、ll 或 L
- hh 表示将相应的参数按 signed char 或 unsigned char 类型输出
- h 表示将相应的参数按 short 或 unsigned short 类型输出
- l 表示将相应的参数按 long 或 unsigned long 类型输出
- ll 表示将相应的参数按 long long 或 unsigned long long 类型输出
- L 表示将相应的参数按 long double 类型输出
2、… 附加参数
该参数的个数由格式化字符串决定。
每个参数的值应当与前面格式化字符串中的占位符类型和位置一一对应。
返回值:
如果函数调用成功,返回值是实际打印的字符数(不包含表示字符串结束的 ‘\0’);
如果函数调用失败,返回值是一个负数。
#include <stdio.h>
int main()
{
int a = 520;
char b = 'F';
float c = 3.14;
double d = 3.141592653;
printf("鱼C工作室创办于2010年的%d\n", a);
printf("I love %cishC.com!\n", b);
printf("圆周率是:%.2f\n", c);
printf("精确到小数点后9位的圆周率是:%11.9f\n", d);
return 0;
}
转义字符
在 C 语言中,用双引号括起来的内容我们称之为字符串,也就是我们平时所说的文本。
字符串可以由可见字符和转义字符组成,像课堂上演示那条鱼的主要组成部分——星号(*),就是可见字符。可见字符就是你输入什么,显示出来就是什么。
而你如果想将一个字符串分为两行来显示,那么你就需要使用到转义字符。
转义字符一般是表示特殊含义的非可见字符,以反斜杠开头:
反斜杠
反斜杠的奥义
在字符串中反斜杠 + 字符是转义字符,表示特殊含义。
但反斜杠如果后边不带任何字符(直接换行),表示我们希望 C 语言将该行以及下一行看做是一个整体。