Cris.Q

Back

一份莫名其妙的C语言速查表Blur image

输入读取#

读取整行字符串(包括空格)#

char line[200];
fgets(line, sizeof(line), stdin);
c

连续读多行直到 EOF#

char s[200];
while (fgets(s, sizeof(s), stdin)) { 
	// 处理每一行 
}
c

处理单行多元素输入#

strtok 分割:

char s[200]; 
fgets(s, sizeof(s), stdin); char *p = strtok(s, ",");
while (p != NULL) {
	int x = atoi(p); 
	// 用 x 
	p = strtok(NULL, ","); // 从原位置继续往后切
}
c

用空格分开时将 strtok 的分隔符设置成空格即可。

对于存入数组的情况:

char line[200];
int arr[50], cnt = 0;
fgets(line, sizeof(line), stdin);
char *p = strtok(line, " ");
while (p != NULL) {
	arr[cnt++] = atoi(p);
	p = strtok(NULL, " ");
}
c

连续读取未知数量数字直到换行#

int x;
while (scanf("%d", &x) == 1) { 
	// 用 x 
	if (getchar() == '\n') 
		break; 
		// 换行就停 
}
c

读取带空格的单词,直到遇到换行#

示例输入:
apple banana orange

char s[100]; 
while (scanf("%s", s) == 1) { 
	// 处理 s 
	if (getchar() == '\n') 
		break; 
}
c

字符串 → 数组 → 排序#

char line[200];
int arr[100], cnt = 0;

// 读取整行
if (fgets(line, sizeof(line), stdin) == NULL) return 0;

// strtok 分割(空格分隔)
char *p = strtok(line, " \n"); // 顺便把 '\n' 也当分隔符
while (p != NULL) {
    arr[cnt++] = atoi(p);
    p = strtok(NULL, " \n");
}

// 排序
qsort(arr, cnt, sizeof(int), cmp);
c

字符串处理#

记得要引入 string.h 才能使用下列方法

长度/比较#

#include <string.h>
size_t len = strlen(s); 
int r = strcmp(a, b); // <0, =0, >0
c

子串检索#

char* p = strchr(s, 'x');   // 第一次出现 'x' 的位置
char* q = strstr(s, "abc"); // 第一次出现子串 "abc"的位置
c

分割字符串#

#include <string.h> 
char line[200]; 
fgets(line, sizeof(line), stdin); 
for(char* p = strtok(line, " ,\n"); p; p = strtok(NULL, " ,\n"))
{ 
	// p 是每个 token
}
c

类型处理#

记得要引入 ctype.h 才能使用下列方法

  • isdigit:是否是数字字符 '0'..'9'
  • isalnum:是否是字母或数字(混合判断)
  • isspace:是否是空白字符(空格、换行、Tab 等)
  • islower / isupper:是否是小写 / 大写字母
  • tolower / toupper:大小写转换

这几个因为用法太显而易见了就不给示例了。

妙妙工具#

Qsort#

记得引入 stdlib.h。基本用法形如:

qsort(base, n, size, cmp);
c
  • base:数组首地址(比如 arr
  • n:元素个数
  • size:每个元素的字节数(通常 sizeof(arr[0])
  • cmp:比较函数指针(你自己写,决定升序/降序/按什么字段排)

使用示例:

给 int 数组升序排序#

#include <stdio.h>
#include <stdlib.h>
int cmp_int_asc(const void *a, const void *b) {
	int x = *(const int*)a;
	int y = *(const int*)b;
	return (x > y) - (x < y); // 避免 x-y 溢出 
}

int main() {
	int arr[] = {10, 3, 25, -7, 8};
	int n = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, n, sizeof(arr[0]), cmp_int_asc);
	
	for (int i = 0; i < n; i++)
		printf("%d ", arr[i]);
	return 0;
}
c

排结构体#

假设要按 score 升序排,score 相同按 id 升序:

typedef struct {
	int id;
	int score;
} Node;

int cmp_node(const void *a, const void *b) {
	const Node *x = (const Node*)a;
	const Node *y = (const Node*)b;
	if (x->score != y->score)
		return (x->score > y->score) - (x->score < y->score);
	return (x->id > y->id) - (x->id < y->id);
}

int main() {
	qsort(nodes, n, sizeof(nodes[0]), cmp_node);
}
c

Printf 格串#

补零(或者补别的什么)#

printf("%05d\n", 42);   // 00042
printf("%02d:%02d\n", 3, 7); // 03:07
c

精度(保留位数)#

浮点:控制小数位数(四舍五入)#

printf("%.2f\n", 3.14159); // 3.14 
printf("%.0f\n", 3.9);     // 4
c

字符串:最大输出长度#

printf("%.3s\n", "abcdef"); // abc
c

动态宽度/精度#

宽度由参数给:

int w = 8; 
printf("^%0*d^\n", w, 123); // "^00000123^"
c

内存操作#

malloc:申请一块未初始化的内存#

特点:申请到的内容是垃圾值,要手动初始化。

int n = 10;
int *a = (int*)malloc(n * sizeof(int)); // 申请10个int  
if (a == NULL) {     
	// 内存不足
}
c

calloc:申请 + 自动清零#

int n = 10;
int *a = (int*)calloc(n, sizeof(int)); // 10个int,全部为0
c

(这俩都是用完要 free() 的,你最好别忘了)

Memset#

int a[100]; memset(a, 0, sizeof(a));
c

Memcpy#

int a[5] = {1,2,3,4,5};
int b[5];
memcpy(b, a, sizeof(a));
c

文化常识(确信)#

ASCII 相关#

计数排序必需品:

  • 大写字母范围是 65 ~ 90
  • 小写字母范围是 97 ~ 122
  • '0' = 48
  • '9' = 57

标准 ASCII 可打印字符是:

  • 32 ~ 126(共 95 个)
  • 其中 32 是空格 ' '

位运算#

&按位与操作,按二进制位进行”与”运算(A & B) 将得到 12 即为 0000 1100
|按位或运算符,按二进制位进行”或”运算(A | B) 将得到 61 即为 0011 1101
^异或运算符,按二进制位进行”异或”运算(A ^ B) 将得到 49 即为 0011 0001
~取反运算符,按二进制位进行”取反”运算(~A) 将得到 -61 即为 1100 0011
<<二进制左移运算符A << 2 将得到 240 即为 1111 0000
>>二进制右移运算符A >> 2 将得到 15 即为 0000 1111

Break & continue#

Break 跳出整个循环体,continue 步出单次循环

数组指针 & 指针数组#

指针数组#

int *p[3];
c

含义:p 是一个长度为 3 的数组,p[i]int*

char *s[3] = {"aa", "bb", "cc"};
printf("%s\n", s[1]); // bb
c

数组指针#

int (*p)[3];
c
int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] = a;      // 指向第0行
printf("%d\n", p[1][2]); // 6
c

二维数组#

int a[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};
// a 是一个2个元素的数组,每个元素是一个3个元素的数组
// 也就是:int[3] t[2]; 本质上 [3] 和 int 配对
c

行指针 & 列指针#

行指针#

行指针 = 指向“一整行”的指针
也就是:指向 int[列数] 这种数组的指针。

如果有 4 列:

int (*row)[4];
c
  • row 指向第 0 行
  • row + 1 指向第 1 行(因为它知道“一行有 4 个 int”)
  • row[i][j] 可以直接当二维数组用

列指针(其实就是普通的元素指针)#

int *p = &a[0][0];
c

此时 p + n 指向的元素是:

  • 第几行:row = n / C
  • 第几列:col = n % C

结构体#

结构体的声明(反正我直接用 typedef 了)

typedef struct {
	int x;
	int y;
} Point; // 相当于将一个匿名结构体绑定给 Point 了

Point p = {0, 0};
c

允许函数以结构体为返回值,此时发生拷贝。

判断傻逼类型注释的技巧#

从右向左螺旋读,遇到括号时被“挡住”。 例如对于这个愚蠢至极的数组指针定义:

int (*p)[3];
c

这次括号把 *p 绑定在一起了:

p 开始读:

  • (*p):说明 p 是指针(因为要先解引用)
  • (*p)[3]:解引用后得到的东西是数组(长度 3)

所以它是数组指针p 是指针,指向“3 个 int 的数组”

一份莫名其妙的C语言速查表
https://crisq.top/blog/c_cheatsheet
Author Cris.Q
Published at 2026年1月16日
Comment seems to stuck. Try to refresh?✨