ASCII码
ASCII码表
字符串和\0(双引号括起来的⼀串字符)
#include <stdio.h>
int main()
{
char arr1[] = {'a', 'b', 'c', '\0'};
char arr2[] = "abc";
char arr3[] = {'a', 'b', 'c', '\0'};
printf("%s\n", arr1);//abc
printf("%s\n", arr2);//abc
printf("%s\n", arr3);//abc烫烫烫?^&%*
printf("%s\n", "abc\0def");
return 0;
}
转义字符
注释会被替换
数据类型

sizeof操作符
#include <stdio.h>
int main()
{
printf("%zd\n", sizeof(char));//1
printf("%zd\n", sizeof(_Bool));//1
printf("%zd\n", sizeof(short));//2
printf("%zd\n", sizeof(int));//4
printf("%zd\n", sizeof(long));//4
printf("%zd\n", sizeof(long long));//8
printf("%zd\n", sizeof(float));//4
printf("%zd\n", sizeof(double));//8
printf("%zd\n", sizeof(long double));//8
return 0;
}
signed和unsigned
% (计算时的正负号)
#include <stdio.h>
int main()
{
printf("%d\n", 11 % -5); // 1
printf("%d\n",-11 % -5); // -1
printf("%d\n",-11 % 5); // -1
return 0;
}
占位符
输出格式(限定宽度)
#include <stdio.h>
int main()
{
printf("%5d\n", 123); // 输出为 " 123"
return 0;
}
//%5d 表⽰这个占位符的宽度⾄少为5位。如果不满5位,对应的值的前⾯会添加空格。输出的值默认是右对⻬,即输出内容前⾯会有空格;如果希望改成左对⻬,在输出内容后⾯添加空格,可以在占位符的 % 的后⾯插⼊⼀个-号
printf("%-5d\n", 123); // 输出为 "123 "
// 输出 " 123.450000"
#include <stdio.h>
int main()
{
printf("%12f\n", 123.45);
return 0;
}
//%12f 表⽰输出的浮点数最少要占据12位。由于⼩数的默认显⽰精度是⼩数点后6位,所以 123.45 输出结果的头部会添加2个空格
显示正负号
#include <stdio.h>
int main()
{
printf("%+d\n", 12); // 输出 +12
printf("%+d\n", -12); // 输出 -12
return 0;
}
限定小数位数
#include <stdio.h>
int main()
{
printf("%*.*f\n", 6, 2, 0.5);
return 0;
}
// 等同于printf("%6.2f\n", 0.5);
输出部分字符串
scanf
占位符
赋值忽略符
#include <stdio.h>
int main()
{
int year = 0;
int month = 0;
int day = 0;
scanf("%d-%d-%d", &year, &month, &day);
printf("%d %d %d\n", year, month, day);
return 0;
}
//如果⽤⼾输⼊ 2020-01-01 ,就会正确解读出年、⽉、⽇。问题是⽤⼾可能输⼊其他格式,⽐如 2020/01/01 ,这种情况下, scanf() 解析数据就会失败
//只要把 * 加在任何占位符的百分号后⾯,该占位符就不会返回值,解析后将被丢弃
//scanf("%d%*c%d%*c%d", &year, &month, &day);
分支语句
if语句
语法结构:
if(表达式) 语句;
if(表达式)
语句1;
else
语句2;
//多分支
if(表达式1)
语句1;
else if(表达式2)
语句2;
else
语句3;
//如果条件成立,要执行多条语句
#include <stdio.h>
int main()
{
if(表达式)
{
语句列表1;
}
else
{
语句列表2;
}
return 0;
}
#include <stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if(age<18)
{
printf("少年\n");
}
else if(age>=18 && age<30)
{
printf("青年\n");
}
else if(age>=30 && age<50)
{
printf("中年\n");
}
else if(age>=50 && age<80)
{
printf("老年\n");
}
else
{
printf("老寿星\n");
}
}
悬空else(else是和它离的最近的if匹配的)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if (a == 1)//当满足该条件才会进入下一个if语句
if (b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
//改进:加大括号
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
{
if(b == 2)
{
printf("hehe\n");
}
}
else
{
printf("haha\n");
}
return 0;
}
练习
1. 判断一个数是否为奇数
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
size_t n = 0;
scanf("%zd", &n);
if (n % 2 == 0)
{
printf("%zd是偶数", n);
}
else
{
printf("%zd是奇数", n);
}
}
2. 输出1-100之间的奇数
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
for (int i = 1; i <= 100; i++)
{
if (i % 2 != 0)
{
printf("%d ", i);
}
}
}
switch语句
switch(整型表达式)
{
case 整形常量表达式:
语句;
}
break语句 的实际效果是把语句列表划分为不同的分支部分
在最后一个 case 语句的后面加上一条 break语句。
(之所以这么写是可以避免出现在以前的最后一个 case 语句后面忘了添加 break语句)
不想忽略不匹配所有标签的表达式的值时该怎么办呢?
你可以在语句列表中增加一条default子句,每个switch语句中只能出现一条default子句
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int day = 0;
switch (day)
{
case 1:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
printf("星期六\n");
break;
case 7:
printf("星期天\n");
break;
}
return 0;
}
//改进
//1. 输入1-5,输出的是“weekday”;
//2. 输入6-7,输出“weekend”
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int day = 0;
switch (day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");
break;
case 6:
case 7:
printf("weekend\n");
break;
}
return 0;
}
循环语句
while
while(表达式)
循环语句;
#include <stdio.h>
int main()
{
int i = 1;
while(i<=10)
{
printf("%d ", i);//1 2 3 4 5 6 7 8 9 10
i = i+1;
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);//521
while (n)
{
printf("%d ", n % 10);//1 2 5
n = n / 10;
}
return 0;
}
while语句中的break和continue
break在while循环中的作用:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的
continue在while循环中的作用就是:
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,
而是直接跳转到while语句的判断部分。进行下一次循环的入口判断
for循环
for(表达式1; 表达式2; 表达式3)
语句;//如果循环体想包含更多的语句,可以加上⼤括号
//表达式1⽤于循环变量的初始化
//表达式2⽤于循环结束条件的判断
//表达式3⽤于循环变量的调整
#include <stdio.h>
int main()
{
int i = 0;
for(i=1; i<=10; i++)
{
printf("%d ", i);
}
return 0;
}
do-while循环
do
语句;
while(表达式);
#include <stdio.h>
int main()
{
int i = 1;
do
{
printf("%d ", i);
i = i + 1;
}while(i<=10);
return 0;
}
break和continue语句
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break;//当i等于5后,就执⾏break,循环就终⽌了
printf("%d ", i);
i = i + 1;
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
//当i等于5后,就执⾏continue,直接跳过continue的代码,去循环的判断的地⽅
//因为这⾥跳过了i = i+1,所以i⼀直为5,程序陷⼊和死循环
printf("%d ", i);
i = i + 1;
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 1;
for (i = 1; i <= 10; i++)
{
if (i == 5)
break;
printf("%d ", i);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 1;
for (i = 1; i <= 10; i++)
{
if (i == 5)
continue;//这⾥continue跳过了后边的打印,来到了i++的调整部分
printf("%d ", i);
}
return 0;
}
for循环嵌套
判断是否为素数
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
for (int i = 100; i <= 200; i++)
{
int flag = 1;//标记是否为素数
for (int j = 2; j < i; j++)
{
if (i % j == 0)
{
flag = 0;
break;//能被除1和自身之外的数整除,不是素数
}
}
if (flag == 1) printf("%d ", i);
}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include <math.h>
//sqrt- 库函数- 开平方的
int main()
{
//产生100~200之间的数
int i = 0;
int count = 0;
for (i = 101; i <= 200; i += 2)
{
int flag = 1;//假设i是素数
//产生的i就是100到200之间的数字
//每次循环进来产生一个i,这个时候判断i是否是素数
//方法是:产生2~i-1之间的数字,去试除i
int j = 0;
for (j = 2; j <= sqrt(i); j++)
{
if (i % j == 0)
{
flag = 0;//表示i不是素数
break;
}
}
if (flag == 1)
{
printf("%d ", i);
count++;
}
}
printf("\ncount = %d\n", count);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
for (i=0; i < 5; i++)
{
for (j=0; j < 5; j++)
{
printf("hehe\n");
}
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
for (; i < 5; i++)
{
for (; j < 5; j++)//i=0时,进入第二层循环,当j=5跳出循环,当i=1时,j仍然为5,进入不了第
//二层循环
{
printf("hehe\n");
}
}
return 0;
}
goto语句
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
printf("hehe\n");
goto next;
printf("haha\n");
next:
printf("跳过了haha的打印\n");
return 0;
}
猜数字游戏
rand
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
}
srand
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
//使⽤time函数的返回值设置种⼦
//因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换
srand((unsigned int)time(NULL));
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
printf("%d\n", rand());
return 0;
}
time
设置随机数的范围
#include <stdlib.h>
#include <time.h>
//函数
void menu()
{
printf("************************\n");
printf("****** 1. play *******\n");
printf("****** 0. exit *******\n");
printf("************************\n");
}
//猜数字游戏的实现
void game()
{
//1. 生成随机数(1~100)
int ret = rand() % 100 + 1;//1~100
//n%100 余数的取值的范围 0~99
//2. 猜数字
int guess = 0;
int count = 5;
while (count)
{
printf("请猜数字:>");
scanf("%d", &guess);
if (guess < ret)
{
printf("猜小了\n");
}
else if (guess > ret)
{
printf("猜大了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;
}
count--;
}
if (count == 0)
{
printf("猜失败了,正确的数字是:%d\n", ret);
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//种子设置只需要一次
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
数组
初始化
//完全初始化
int arr[5] = {1,2,3,4,5};
//不完全初始化
int arr2[6] = {1};//第⼀个元素初始化为1,剩余的元素默认初始化为0
//错误的初始化 - 初始化项太多
int arr3[3] = {1, 2, 3, 4};
⼀维数组在内存中的存储
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
{
printf("&arr[%d] = %p\n ", i, &arr[i]);
}
return 0;
}
sizeof计算数组元素个数(计算类型或者变量⼤⼩,计算数组的⼤⼩)
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
return 0;
}
//输出的结果是40,计算的是数组所占内存空间的总⼤⼩,单位是字节
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr[0]));//计算⼀个元素的⼤⼩,单位是字节
return 0;
}
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
return 0;
}
二维数组
初始化
⼆维数组在内存中的存储
#include <stdio.h>
int main()
{
int arr[3][5] = { 0 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
C99中的变⻓数组
int arr1[10];
int arr2[3+5];
int arr3[] = {1,2,3};
int n = a+b;
int arr[n];
//数组 arr 就是变⻓数组,因为它的⻓度取决于变量 n 的值,编译器没法事先确定,只
有运⾏时才能知道 n 是多少
//变⻓数组的根本特征,就是数组⻓度只有运⾏时才能确定,所以变⻓数组不能初始化。它的好处是程
序员不必在开发时,随意为数组指定⼀个估计的⻓度,程序可以在运⾏时为数组分配精确的⻓度。有
⼀个⽐较迷惑的点,变⻓数组的意思是数组的⼤⼩是可以使⽤变量来指定的,在程序运⾏的时候,根
据变量的⼤⼩来指定数组的元素个数,⽽不是说数组的⼤⼩是可变的。数组的⼤⼩⼀旦确定就不能再
变化了
//VS2022上,虽然⽀持⼤部分C99的语法,没有⽀持C99中的变⻓数组,没法测试;
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
int arr[n];
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
return 0;
}//gcc
数组练习
练习1:多个字符从两端移动,向中间汇聚
#include <stdio.h>
int main()
{
char arr1[] = "welcome to bit...";
char arr2[] = "#################";
int left = 0;
int right = strlen(arr1) - 1;
printf("%s\n", arr2);
while (left <= right)
{
Sleep(1000);
arr2[left] = arr1[left];
arr2[right] = arr1[right];
left++;
right--;
printf("%s\n", arr2);
}
return 0;
}
练习2:⼆分查找
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int left = 0;
int right = sizeof(arr) / sizeof(arr[0]) - 1;
int key = 7;//要找的数字
int mid = 0;//记录中间元素的下标
int find = 0;
while (left <= right)
{
mid = (left + right) / 2;
//mid = left+(right-left)/2;
if (arr[mid] > key)
{
right = mid - 1;
}
else if (arr[mid] < key)
{
left = mid + 1;
}
else
{
find = 1;
break;
}
}
if (1 == find)
printf("找到了,下标是%d\n", mid);
else
printf("找不到\n");
}
函数
库函数
⾃定义函数
ret_type fun_name(形式参数)
{}
//ret_type 是函数返回类型
//fun_name 是函数名
//括号中放的是形式参数
//{}括起来的是函数体
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 0;
int b = 0;
//输⼊
scanf("%d %d", &a, &b);
//调⽤加法函数,完成a和b的相加
//求和的结果放在r中
int r = Add(a, b);
//输出
printf("%d\n", r);
return 0;
}
形参和实参
return语句
数组做函数参数
#include <stdio.h>
void set_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = -1;
}
}
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
set_arr(arr, sz);//设置数组内容为-1
print_arr(arr, sz);//打印数组内容
return 0;
}
嵌套调⽤和链式访问
#include <stdio.h>
int is_leap_year(int y)
{
if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
return 1;
else
return 0;
}
int get_days_of_month(int y, int m)
{
int days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day = days[m];
if (is_leap_year(y) && m == 2)
day += 1;
return day;
}
int main()
{
int y = 0;
int m = 0;
scanf("%d %d", &y, &m);
int d = get_days_of_month(y, m);
printf("%d\n", d);
return 0;
}
#include <stdio.h>
int main()
{
printf("%d\n", strlen("abcdef"));//链式访问
return 0;
}
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
//4321
//第⼀个printf打印的是第⼆个printf的返回值,第⼆个printf打印的是第三个printf的返回值。
//第三个printf打印43,在屏幕上打印2个字符,再返回2,第⼆个printf打印2,在屏幕上打印1个字符,//再放回1,第⼀个printf打印1
static和extern
static修饰局部变量
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 5; i++)
{
test();
}
return 0;
}
#include <stdio.h>
void test()
{
//static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 5; i++)
{
test();
}
return 0;
}
static修饰全局变量