目录
printf函数中那些%d %f等等的作用
运算符的优先级
选择排序
冒泡排序
快速排序
折半查找
归并排序
strcat
strcpy
scanf可以限制输入格式么
c语言实现链式队列,输入数字入队,输入字符出队。
统计一个范围内的素数
打印水仙花数
打印杨辉三角
链表实现学生管理系统
最近电脑的空间越发的不够用了,非常的难受,为了让自己好受点我决定把那些初学者用的东西都放到博客里然后清理一下以前写的“垃圾”代码。
本文章持续更新中,当前更新时间2024-03-31
printf函数中那些%d %f等等的作用
说明符(specifier) | 对应数据类型 | 描述 |
---|---|---|
d / i | int | 输出类型为有符号的十进制整数,i 是老式写法 |
o | unsigned int | 输出类型为无符号八进制整数(没有前导 0) |
u | unsigned int | 输出类型为无符号十进制整数 |
x / X | unsigned int | 输出类型为无符号十六进制整数,x 对应的是 abcdef,X 对应的是 ABCDEF(没有前导 0x 或者 0X) |
f / lf | double | 输出类型为十进制表示的浮点数,默认精度为6(lf 在 C99 开始加入标准,意思和 f 相同) |
e / E | double | 输出类型为科学计数法表示的数,此处 "e" 的大小写代表在输出时用的 “e” 的大小写,默认浮点数精度为6 |
g | double | 根据数值不同自动选择 %f 或 %e,%e 格式在指数小于-4或指数大于等于精度时用使用 [1] |
G | double | 根据数值不同自动选择 %f 或 %E,%E 格式在指数小于-4或指数大于等于精度时用使用 |
c | char | 输出类型为字符型。可以把输入的数字按照ASCII码相应转换为对应的字符 |
s | char * | 输出类型为字符串。输出字符串中的字符直至遇到字符串中的空字符(字符串以 '\0‘ 结尾,这个 '\0' 即空字符)或者已打印了由精度指定的字符数 |
p | void * | 以16进制形式输出指针 |
% | 不转换参数 | 不进行转换,输出字符‘%’(百分号)本身 |
n | int * | 到此字符之前为止,一共输出的字符个数,不输出文本 [4] |
运算符的优先级
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | |
() | 圆括号 | (表达式)/函数名(形参表) | |||
. | 成员选择(对象) | 对象.成员名 | |||
-> | 成员选择(指针) | 对象指针->成员名 | |||
2 | - | 负号运算符 | -常量 | 右到左 | 单目运算符 |
(type) | 强制类型转换 | (数据类型)表达式 | |||
++ | 自增运算符 | ++变量名 | 单目运算符 | ||
-- | 自减运算符 | --变量名 | 单目运算符 | ||
* | 取值运算符 | *指针变量 | 单目运算符 | ||
& | 取地址运算符 | &变量名 | 单目运算符 | ||
! | 逻辑非运算符 | !表达式 | 单目运算符 | ||
~ | 按位取反运算符 | ~表达式 | 单目运算符 | ||
sizeof | 长度运算符 | sizeof(表达式) | |||
3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | 双目运算符 | ||
% | 余数(取模) | 整型表达式%整型表达式 | 双目运算符 | ||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | 双目运算符 | ||
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | 双目运算符 | ||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | 双目运算符 | ||
< | 小于 | 表达式<表达式 | 双目运算符 | ||
<= | 小于等于 | 表达式<=表达式 | 双目运算符 | ||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | 双目运算符 | ||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 条件运算符 | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | |
/= | 除后赋值 | 变量/=表达式 | |||
*= | 乘后赋值 | 变量*=表达式 | |||
%= | 取模后赋值 | 变量%=表达式 | |||
+= | 加后赋值 | 变量+=表达式 | |||
-= | 减后赋值 | 变量-=表达式 | |||
<<= | 左移后赋值 | 变量<<=表达式 | |||
>>= | 右移后赋值 | 变量>>=表达式 | |||
&= | 按位与后赋值 | 变量&=表达式 | |||
^= | 按位异或后赋值 | 变量^=表达式 | |||
|= | 按位或后赋值 | 变量|=表达式 | |||
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 | 从左向右顺序运算 |
选择排序
选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理是首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
以下是用C语言实现选择排序的示例代码:
#include <stdio.h> void swap(int* a, int* b) { int t = *a; *a = *b; *b = t;
} void selectionSort(int arr[], int n) { int i, j, min_idx; for (i = 0; i < n-1; i++) { min_idx = i; for (j = i+1; j < n; j++) if (arr[j] < arr[min_idx]) min_idx = j; swap(&arr[min_idx], &arr[i]); }
} void printArray(int arr[], int size) { int i; for (i=0; i < size; i++) printf("%d ", arr[i]); printf("\n");
} int main() { int arr[] = {64, 25, 12, 22, 11}; int n = sizeof(arr)/sizeof(arr[0]); selectionSort(arr, n); printf("Sorted array: \n"); printArray(arr, n); return 0;
}
冒泡排序
冒泡排序(Bubble Sort)是一种简单的排序算法,它重复地遍历待排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
以下是用C语言实现冒泡排序的示例代码:
#include <stdio.h> void bubbleSort(int arr[], int n) { int i, j, temp; for (i = 0; i < n-1; i++) { for (j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) { // 交换 arr[j] 和 arr[j+1] temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } }
} void printArray(int arr[], int size) { int i; for (i=0; i < size; i++) printf("%d ", arr[i]); printf("\n");
} int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; int n = sizeof(arr)/sizeof(arr[0]); bubbleSort(arr, n); printf("Sorted array: \n"); printArray(arr, n); return 0;
}
快速排序
快速排序(Quick Sort)是一种高效的排序算法,它采用了分而治之(Divide and Conquer)的思想。首先选择一个基准元素,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比基准元素小,另一部分的所有数据都比基准元素大,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
以下是使用C语言实现快速排序的示例代码:
#include <stdio.h> void swap(int* a, int* b) { int t = *a; *a = *b; *b = t;
} int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选择最右边的元素作为基准 int i = (low - 1); // 指向最小元素的指针 for (int j = low; j <= high - 1; j++) { // 如果当前元素小于或等于基准 if (arr[j] < pivot) { i++; // 增加最小元素的指针 swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1);
} void quickSort(int arr[], int low, int high) { if (low < high) { /* pi 是分区索引,arr[p] 现在在正确的位置 */ int pi = partition(arr, low, high); // 分别对基准元素两侧的子序列进行快速排序 quickSort(arr, low, pi - 1); // 对基准元素左边的子序列进行递归排序 quickSort(arr, pi + 1, high); // 对基准元素右边的子序列进行递归排序 }
} void printArray(int arr[], int size) { int i; for (i = 0; i < size; i++) printf("%d ", arr[i]); printf("\n");
} int main() { int arr[] = {10, 7, 8, 9, 1, 5}; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n - 1); printf("Sorted array: \n"); printArray(arr, n); return 0;
}
折半查找
折半查找(也称为二分查找)是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。
以下是用C语言实现折半查找的示例代码:
#include <stdio.h> int binarySearch(int arr[], int l, int r, int x) { if (r >= l) { int mid = l + (r - l) / 2; // 如果 mid 是要查找的元素 if (arr[mid] == x) return mid; // 如果 mid 大于要查找的元素,只需在左半部分查找 if (arr[mid] > x) return binarySearch(arr, l, mid - 1, x); // 否则在右半部分查找 return binarySearch(arr, mid + 1, r, x); } // 我们到达了这里,说明元素不在数组中 return -1;
} void printArray(int arr[], int size) { int i; for (i = 0; i < size; i++) printf("%d ", arr[i]); printf("\n");
} int main(void) { int arr[] = {2, 3, 4, 10, 40}; int n = sizeof(arr) / sizeof(arr[0]); int x = 10; int result = binarySearch(arr, 0, n - 1, x); (result == -1) ? printf("元素不在数组中\n") : printf("元素在数组的索引为 %d\n", result); return 0;
}
归并排序
归并排序(Merge Sort)是一种典型的分治思想的排序算法。它将待排序的序列划分为若干个子序列,每个子序列是一个有序的序列。然后再把有序子序列合并为整体有序序列。
以下是归并排序的基本步骤:
- 分解:将数组分解成两个较小的子数组,直到子数组的大小为1。
- 递归进行排序并合并:递归地对子数组进行排序,并将已排序的子数组合并成一个大的有序数组,直到合并为1个完整的数组。
下面是一个简单的C语言实现:
#include <stdio.h> void merge(int arr[], int l, int m, int r) { int i, j, k; int n1 = m - l + 1; int n2 = r - m; /* 创建临时数组 */ int L[n1], R[n2]; /* 拷贝数据到临时数组 L[] 和 R[] */ for (i = 0; i < n1; i++) L[i] = arr[l + i]; for (j = 0; j < n2; j++) R[j] = arr[m + 1 + j]; /* 合并临时数组回 arr[l..r] */ i = 0; j = 0; k = l; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } /* 拷贝 L[] 的剩余元素到 arr */ while (i < n1) { arr[k] = L[i]; i++; k++; } /* 拷贝 R[] 的剩余元素到 arr */ while (j < n2) { arr[k] = R[j]; j++; k++; }
} void mergeSort(int arr[], int l, int r) { if (l < r) { // 找到中间点 int m = l + (r - l) / 2; // 对左边子数组进行归并排序 mergeSort(arr, l, m); // 对右边子数组进行归并排序 mergeSort(arr, m + 1, r); // 合并两个已排序的子数组 merge(arr, l, m, r); }
} /* 打印数组 */
void printArray(int arr[], int size) { int i; for (i = 0; i < size; i++) printf("%d ", arr[i]); printf("\n");
} /* 测试代码 */
int main() { int arr[] = {12, 11, 13, 5, 6, 7}; int arr_size = sizeof(arr) / sizeof(arr[0]); printf("原始数组: \n"); printArray(arr, arr_size); mergeSort(arr, 0, arr_size - 1); printf("排序后的数组: \n"); printArray(arr, arr_size); return 0;
}
strcat
在C语言中,strcat
函数用于将一个字符串(源字符串)连接到另一个字符串(目标字符串)的末尾。这个函数是标准库函数,定义在<string.h>
头文件中。
下面是strcat
函数的基本实现
#include <stdio.h> char* my_strcat(char* dest, const char* src) { char* ret = dest; // 找到dest字符串的结尾 while (*dest) { dest++; } // 将src字符串的内容复制到dest字符串的结尾 while (*src) { *dest++ = *src++; } // 在新字符串的结尾添加空字符 *dest = '\0'; return ret;
} int main() { char dest[100] = "Hello, "; char src[] = "World!"; my_strcat(dest, src); printf("%s\n", dest); // 输出:Hello, World! return 0;
}
在这个例子中,my_strcat
函数接受两个参数:dest
(目标字符串)和src
(源字符串)。它首先找到dest
字符串的结尾,然后将src
字符串的内容复制到dest
字符串的结尾。最后,它在新的字符串的结尾添加了一个空字符(\0
),这是C字符串的必要组成部分。函数返回的是目标字符串的原始地址。
注意,这个实现假设dest
字符串有足够的空间来容纳src
字符串的内容。如果dest
字符串的空间不足以容纳src
字符串的内容,那么结果将是未定义的,可能会导致缓冲区溢出错误。在实际使用中,你应该确保目标字符串有足够的空间来容纳源字符串的内容。
strcpy
strcpy
是一个用于复制字符串的C标准库函数,定义在 <string.h>
头文件中。该函数将一个字符串(包括空字符)复制到另一个字符串中。下面是一个简单的 strcpy
函数的实现:
#include <stdio.h> char* my_strcpy(char* dest, const char* src) { char* ret = dest; // 保存目标字符串的起始地址,以便返回 // 复制字符,直到遇到源字符串的空字符 while (*src != '\0') { *dest++ = *src++; } // 在目标字符串的末尾添加空字符 *dest = '\0'; return ret; // 返回目标字符串的起始地址
} int main() { char dest[100]; const char* src = "Hello, world!"; my_strcpy(dest, src); printf("%s\n", dest); // 输出:Hello, world! return 0;
}
scanf可以限制输入格式么
scanf
函数在 C 语言中用于从标准输入(通常是键盘)读取并格式化数据。然而,scanf
的格式说明符并不像 printf
中的那样强大,它不支持直接指定浮点数的小数点后的位数,如 %.1f
这样的格式。
例如,printf
中的 %.1f
用于打印浮点数时保留一位小数,但 scanf
中没有这样的选项。scanf
中的 %f
用于读取浮点数,它会读取尽可能多的数字,直到遇到非数字字符为止,而不会限制小数点后的位数。
c语言实现链式队列,输入数字入队,输入字符出队。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h> // 定义链式队列的节点结构体
typedef struct QueueNode { int data; struct QueueNode* next;
} QueueNode; // 定义链式队列的结构体
typedef struct { QueueNode* front; // 队头指针 QueueNode* rear; // 队尾指针
} LinkQueue; // 初始化链式队列
void InitQueue(LinkQueue* q) { q->front = q->rear = (QueueNode*)malloc(sizeof(QueueNode)); if (!q->front) { exit(1); // 申请空间失败 } q->front->next = NULL;
} // 判断链式队列是否为空
int IsEmpty(LinkQueue* q) { return q->front == q->rear;
} // 入队操作
void EnQueue(LinkQueue* q, int e) { QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode)); if (!newNode) { exit(1); // 申请空间失败 } newNode->data = e; newNode->next = NULL; q->rear->next = newNode; q->rear = newNode;
} // 出队操作
int DeQueue(LinkQueue* q) { if (IsEmpty(q)) { return -1; // 队列为空,无法出队 } QueueNode* temp = q->front->next; int e = temp->data; q->front->next = temp->next; if (q->rear == temp) { // 如果删除的节点是队尾节点 q->rear = q->front; } free(temp); return e;
} // 打印队列内容
void PrintQueue(LinkQueue* q) { QueueNode* p = q->front->next; printf("队列内容为:"); while (p) { printf("%d ", p->data); p = p->next; } printf("\n");
} int main() { LinkQueue q; InitQueue(&q); char input; int num; printf("请输入数字入队,输入字符出队(输入'q'退出):\n"); while (1) { scanf(" %c", &input); // 注意%c前面有一个空格,用于跳过前面的空白字符 if (input == 'q') { break; } else if (isdigit(input)) { // 判断输入是否为数字 num = input - '0'; EnQueue(&q, num); printf("数字%d入队成功\n", num); } else { // 输入字符则出队 int e = DeQueue(&q); if (e != -1) { printf("出队元素为:%d\n", e); } else { printf("队列为空,无法出队\n"); } } PrintQueue(&q); // 每次操作后打印队列内容 } // 释放队列占用的内存空间 printf("开始释放队列内存...\n"); QueueNode* p = q.front->next; // 跳过哨兵节点 while (p) { QueueNode* temp = p; p = p->next; free(temp); } free(q.front); // 释放哨兵节点 printf("队列内存释放完毕!\n"); return 0;
}
统计一个范围内的素数
要统计一个给定范围内素数的个数,我们需要遍历该范围内的所有整数,并检查每个整数是否是素数。素数是一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数。
以下是一个用C语言实现的简单程序,用于统计给定范围内素数的个数:
#include <stdio.h>
#include <stdbool.h> // 函数用于检查一个数是否是素数
bool isPrime(int num) { if (num <= 1) { return false; } for (int i = 2; i * i <= num; i++) { if (num % i == 0) { return false; } } return true;
} // 函数用于统计给定范围内素数的个数
int countPrimes(int start, int end) { int count = 0; for (int i = start; i <= end; i++) { if (isPrime(i)) { count++; } } return count;
} int main() { int start, end; printf("请输入起始和结束数字(用空格分隔): "); scanf("%d %d", &start, &end); if (start > end) { printf("起始数字不能大于结束数字。\n"); return 1; } int primeCount = countPrimes(start, end); printf("在范围 [%d, %d] 内有 %d 个素数。\n", start, end, primeCount); return 0;
}
打印水仙花数
水仙花数(Narcissistic Number)也被称为阿姆斯特朗数(Armstrong Number),它是一个 n 位数,其每个位上的数字的 n 次幂之和等于它本身。例如,153 是一个 3 位数的水仙花数,因为 1^3 + 5^3 + 3^3 = 153。
以下是一个用 C 语言编写的程序,用于打印指定范围内的所有水仙花数:
#include <stdio.h>
#include <math.h> // 函数用于检查一个数是否是水仙花数
int isNarcissistic(int num) { int originalNum = num; int sum = 0; int digits = (int)log10(num) + 1; // 计算数字的位数 while (num > 0) { int digit = num % 10; // 获取最后一位数字 sum += pow(digit, digits); // 将该位数字的位数次幂加到总和中 num /= 10; // 去掉最后一位数字 } return sum == originalNum; // 如果总和等于原数,则是水仙花数
} int main() { int start, end; printf("请输入起始和结束数字(用空格分隔): "); scanf("%d %d", &start, &end); printf("范围内的水仙花数有:\n"); for (int i = start; i <= end; i++) { if (isNarcissistic(i)) { printf("%d ", i); } } printf("\n"); return 0;
}
打印杨辉三角
杨辉三角(Pascal's Triangle)是一个在数学中常见的二维数表,它可以用组合数来表示。在杨辉三角中,每个数是它肩上的两个数之和。第一行和第一列都是1,其它位置的数都是它肩上的两个数之和。
以下是一个用C语言实现的简单程序,用于打印指定行数的杨辉三角:
#include <stdio.h> void printPascalTriangle(int numRows) { int triangle[numRows][numRows]; // 初始化第一列和对角线上的元素为1 for (int i = 0; i < numRows; i++) { triangle[i][0] = 1; triangle[i][i] = 1; } // 计算并打印其余元素 for (int i = 2; i < numRows; i++) { for (int j = 1; j < i; j++) { triangle[i][j] = triangle[i - 1][j - 1] + triangle[i - 1][j]; printf("%d ", triangle[i][j]); } printf("\n"); }
} int main() { int numRows; printf("请输入要打印的杨辉三角的行数: "); scanf("%d", &numRows); printPascalTriangle(numRows); return 0;
}
链表实现学生管理系统
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // 学生信息结构体
typedef struct Student { char name[50]; int age; float score;
} Student; // 链表节点结构体
typedef struct Node { Student data; struct Node* next;
} Node; // 创建新节点
Node* createNode(Student data) { Node* newNode = (Node*)malloc(sizeof(Node)); if (!newNode) { printf("内存分配失败\n"); exit(1); } newNode->data = data; newNode->next = NULL; return newNode;
} // 插入学生到链表末尾
void insertStudent(Node** head, Student data) { Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; } else { Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; }
} // 从链表中删除学生
void deleteStudent(Node** head, char* name) { Node* temp = *head; Node* prev = NULL; while (temp != NULL && strcmp(temp->data.name, name) != 0) { prev = temp; temp = temp->next; } if (temp == NULL) { printf("未找到学生: %s\n", name); return; } if (prev == NULL) { *head = temp->next; } else { prev->next = temp->next; } free(temp);
} // 查找学生信息
Node* findStudent(Node* head, char* name) { Node* temp = head; while (temp != NULL) { if (strcmp(temp->data.name, name) == 0) { return temp; } temp = temp->next; } return NULL;
} // 显示所有学生信息
void displayStudents(Node* head) { Node* temp = head; printf("学生信息如下:\n"); while (temp != NULL) { printf("姓名: %s, 年龄: %d, 分数: %.2f\n", temp->data.name, temp->data.age, temp->data.score); temp = temp->next; }
} // 释放链表内存
void freeList(Node* head) { Node* temp; while (head != NULL) { temp = head; head = head->next; free(temp); }
} int main() { Node* head = NULL; // 插入学生信息 Student student1 = {"张三", 20, 90.5}; Student student2 = {"李四", 21, 85.0}; insertStudent(&head, student1); insertStudent(&head, student2); // 显示所有学生信息 displayStudents(head); // 查找学生信息 Node* foundStudent = findStudent(head, "张三"); if (foundStudent) { printf("找到学生: %s\n", foundStudent->data.name); } else { printf("未找到学生\n"); } // 删除学生信息 deleteStudent(&head, "李四"); printf("\n删除李四后的学生信息:\n"); displayStudents(head); // 释放链表内存 freeList(head); return 0;
}