C语言考点总结
编辑 | 编译 | 链接 | 运行 | 语言 |
---|---|---|---|---|
源文件.c | cl.exe -> .obj | link.exe -> .exe | 运行 | C |
源文件.asm | MASM.exe -> .obj | link.exe -> .exe | 运行 | 汇编 |
编程例题推荐文章: https://blog.csdn.net/liu17234050/article/details/104217830
本文章只记载特殊怪异语法.
规则篇
标识符定义规则
标识符必须以大小写英文字母或者下划线作为首字母.
无语的文字题 (简单收集)
科学计数法语法规则
void Test() {
// [整数|小数]e[+-]整数[lf]
int A = (1e3, 2e6f, 3e6l, 4e+5, 1.2e-6);
}
单引号规则
void Test() {
// 单引号可以放四个内容
printf('ABCD'); // 输出 ABCD
// 单引号赋值时, 取最后一位.
int Test = 'ABCD';
printf("%c", Test); // 输出 D
}
00截断问题
float后缀f的规则
f前面的内容必须是小数.
printf中的float四舍五入问题
注意: 只有float有四舍五入!!!!如果是int则没有!!!
宏定义问题
void Test(){
#define A 1
#define FF A + A
int x = FF * FF; // int x = 1 + 1 * 1 + 1
printf("%d", x); // 输出3
// define关键字可以通过undef进行取消.
#undef A
}
并且, 宏定义不能与变量名冲突, 因为宏定义是常量, 所以宏定义也不允许被修改.
宏定义专升本特别注意事项
常量拓展
void main() {
const int PI = 3.14;
PI = 1234; // 报错
}
进制转换
# include <stdio.h>
void main() {
int Test1 = 012345; // 长度不限制, 八进制
int Test2 = 0X123123123; // 长度不限制, 十六进制, 0x可以写成0X大写形式.
int BaJinZhi1 = 0123; // 长度不限制
char BaJinZhi2 = '\123'; // \ + 3位八进制
printf("%d, %d", BaJinZhi1, BaJinZhi2);
// long ShiLiuJinZhi1 = 0x1000; // 长度不限制
// long ShiLiuJinZhi2 = '\x10'; // \x + 2位16进制, 原因很简单, 字符的ASCII码是 0~127. 不允许超过该范围. 否则出现乱数.
printf("\n 八进制 %o, 十六进制 %x %X %#x %#X", 123, 123, 123, 123, 123);
}
运算符优先级
算数 > 关系 > 逻辑 > 赋值 > 逗号
例题1: 运算
表达式可以写成 x = (x + ((a % 3) * (int)(x + y) % 2) / 4);
赋值规则
从右向左
void Test() {
int exam1 = 10;
int Exam1Result = exam1 += exam1 -= exam1 - exam1; // 结果是 20, 因为赋值是从右向左
int exam2 = 3;
exam2 *= exam2 += exam2 - 2; // 16, 从右向左.
}
函数参数执行优先级 (从后往前)
# include <stdio.h>
int Result(int x){
static int k = 0;
x += k;
k ++;
return x;
}
void main(){
int x = 0;
// 函数参数相同时, 从后往前执行
printf("%d %d", Result(x), Result(x)); // 1 0
getchar();
}
// 经典例题:
# include <stdio.h>
void main(){
int* p;
int a[5] = {4, 3, 5, 6, 1};
p = a;
printf("%d %d \n", *p++, (*p)++);
/*
++ 比 指针优先级高, 又因为函数的参数传递是从后往前.
结果: 5 4
*/
printf("%d \n", *p); // 指针已自动+1, 变成3
getchar();
}
scanf本质 (要地址,可修改数组中的内容)
考试函数标准库文件
<stdio.h>
getchar()
putchar()
scanf()
printf()
puts()
gets()
<string.h>
strcmp()
strlen()
不需要标准库的函数:
sizeof()
技巧篇
右移16位不出0的情况
等价题目
根据题干, 把e设为0, e是0的时候
, 表达式为1. 那么根据e是0 -> 结果1
得出选项A.
一行法阅读程序
+=-=同一表达式
#include "stdio.h"
void main(){
int a = 3;
a += a-= a * a;
/*
解析为:
a = a - a * a
a = a + a
*/
printf("%d", a);
getchar();
}
# include <stdio.h>
void main(){
int a = 5;
// a *= a += a++; // 121
a = a + a++; // a++ 先执行, 后面的是5, 但是前面的a变成了6 结果是 5+6 = 11
a = a * a; // 11 * 11 = 121
getchar();
}
++不允许放到等号左边
当然, 下面这种形式也是错误的.
if 坑点
看到if没带大括号, 第一时间反应第一条语句是谁.
取余公式
a % b = a - a / b * b
取余规则
整数 % 整数
三元运算符嵌套问题
注意加上小括号, 这样方便判断.
for逻辑梳理
void main() {
int i;
for (i = 0; i < 10; i ++) {
printf("\n%d", i); // 输出 0~9
}
printf("%d", i); // i = 10
int i, j;
for (i = 0, j = 0; j < 10; i ++, j +=2 ) {
printf("\n%d, %d", i, j);
/*
0, 0
1, 2
2, 4
3, 6
4, 8
*/
}
printf("\n%d, %d", i, j); // 5, 10
}
for循环作用域问题
# include <stdio.h>
// static 遇到代码块作用域问题
int square(int i){
return i*i;
}
void main(){
int i = 0;
i = square(i);
// int i 不会进入 for(){} 中 {} 的作用域
for(; i < 3; i++){
// static 在 {} 中, 作用域只是在 {} 中.
static int i = 1;
i += square(i);
printf("%d, ", i);
}
printf("\n%d", i);
getchar();
}
进制转换与微机原理的区别 (注意研究)
# include <stdio.h>
// C语言会回到原码.
void main() {
int num = ~2;
printf("%d", num); // 结果是 -3
/*
运算规则:
2 的二进制值: 0010
~2 : 1101 遇到了print, print来对其求补码后输出
[~2]反 : 1010 [~2]补 : 1011 -> -3 (只是输出的时候输出2进制罢了)
和微机原理区别: MOV AL, 2
NOT AL (结果是FD) 1111 1101
*/
/*
2&-3:
2的补码: 00000000 00000000 00000000 00000010
-3的补码:11111111 11111111 11111111 11111101
&操作: 00000000 00000000 00000000 00000000 (结果是正数, 不需要回推)
*/
int result = 2 & -3;
printf("%d", result); // 结果是 0
}
例题分析集合:
# include <stdio.h>
void main() {
int exam1 = ~2;
int exam2 = 2 & 3;
int exam3 = 2 | 3;
int exam4 = ~- 5;
int exam5 = 13 & 7;
int exam6 = 5 | 4;
int exam7 = -3 ^ 3;
printf("%d", exam7);
/*
exam1 分析:
2 补码: 00000000 00000000 00000000 00000010
~取 反: 11111111 11111111 11111111 11111101 (发现是负数, 需要回到原码)
-1回原: 11111111 11111111 11111111 11111100
取反回原:10000000 00000000 00000000 00000011 结果-3
exam2 分析:
2 补码: 00000000 00000000 00000000 00000010
3 补码: 00000000 00000000 00000000 00000011
& 操作: 00000000 00000000 00000000 00000010 (发现正数, 无需回去) 结果2
exam3 分析:
2 补码: 00000000 00000000 00000000 00000010
3 补码: 00000000 00000000 00000000 00000011
| 操作: 00000000 00000000 00000000 00000011 (发现正数, 无需回去) 结果3
exam4 分析:
-5原码: 10000000 00000000 00000000 00000101
-5反码: 11111111 11111111 11111111 11111010
-5补码: 11111111 11111111 11111111 11111011
~ 操作: 00000000 00000000 00000000 00000100 (发现正数, 无需回去) 结果4
exam5 分析:
13补码: 00000000 00000000 00000000 00001101
7 补码: 00000000 00000000 00000000 00000111
& 操作: 00000000 00000000 00000000 00000101 (发现正数, 无需回去) 结果5
exam6 分析:
5 补码: 00000000 00000000 00000000 00000101
4 补码: 00000000 00000000 00000000 00000100
| 操作: 00000000 00000000 00000000 00000101 (发现正数, 无需回去) 结果5
exam7 分析:
-3原码: 10000000 00000000 00000000 00000011
-3反码: 11111111 11111111 11111111 11111100
-3补码: 11111111 11111111 11111111 11111101
3 补码: 00000000 00000000 00000000 00000011
^ 操作: 11111111 11111111 11111111 11111110 (发现负数, 需要回去)
-1操作: 11111111 11111111 11111111 11111101
取 反: 10000000 00000000 00000000 00000010 结果-2
*/
int Test = -2 >> 2;
/*
-2 原码: 10000000 00000000 00000000 00000010
-2 反码: 11111111 11111111 11111111 11111101
-2 补码: 11111111 11111111 11111111 11111110
>> 操作: 11111111 11111111 11111111 11111111 (发现负数, 回原)
-1 操作: 11111111 11111111 11111111 11111110
取反操作: 10000000 00000000 00000000 00000001 结果-1
*/
}
字符串长度问题
从\0
的位置减去首地址, 即可得到长度.
执行顺序问题 (疏忽导致做错)
for while dowhile 循环次数
int i = 0;
while(i < 10){
i++;
printf("i = %d \n", i); // 结果十次
}
int i = 0;
do{
i++;
printf("i = %d \n", i); // 结果十次
}while(i < 10);
for(int i = 0; i < 10; i ++){} // 结果十次
# include <stdio.h>
void main(){
int k = 0;
while(k++ <= 10);
printf("%d", k);
// k = 10 时, 执行了一次 k++
// 第二次判断 又执行了一次 k++
// 结果是 12
getchar();
}
递归题目做题思路
选择&阅读题目特别注意
printf
printf要特别注意:
1. printf到底打印的什么 是%s?%c?%d?%f?等等
2. printf到底在什么条件下才打印
本质篇
函数无定义类型
数组访问的本质
因为数组的传递形式为首地址传递
, 在此发现了一种姿势:
void main() {
int Arr[] = {1,2,3};
printf("%d", Arr[0]); // 正常访问形式: 翻译下来则是 "首地址[0]", 则是 "地址+0 存储单元的内容"
// 引发思考: 是否 首地址[0] 可以取出任何数据的内容
int myNum = 10;
printf("%d", (&myNum) [0] ); // 结果为 10, 思路正确.
}
数组赋值问题
只能在初始化的时候进行赋值!!!
数组与指针唯一的区别
# include <stdio.h>
# include <string.h>
void main(){
char *st = "how are you";
char a[11];
printf("%d", a++); // 代码会报错, 原因是, 数组是固定大小, 不允许自增.
getchar();
getchar();
}
sizeof 取数组长度坑点
因为数组是首地址传递, 实际上TestSize
方法并不知道外部的数据有多少.
指针的几种形式
#include <stdio.h>
#include <stdlib.h>
// 指针的几种形式
void t1() {
int n1 = 10;
int* p1 = &n1;
int** p2 = &p1;
printf("%d %d", *p1, **p2); // 10 10
}
void t2() {
int n1 = 10, n2 = 20, n3 = 30, n4 = 40;
int* p[4];
p[0] = &n1;
p[1] = &n2;
p[2] = &n3;
p[3] = &n4;
printf("%d %d %d %d", **p, p[1][0], *p[2], **(p+3)); // 10 20 30 40
/*
解释:
**p -> p是首地址 -> *p 得到首地址的值, 也就是p[0]的值 -> *p[0] 对 p[0] 的值进行查找值, 结果是n1的值.
p[1][0] -> p[1] 中存放 n2 的地址 -> n2地址[0] 也就是 地址[相对位移量] 的形式, 结果是 n2 的值
*p[2] -> p[2] 是 n3 的地址 -> *n3的地址 则找到 n3 的值
**(p+3) -> p是首地址, 然后+3, 则是p数组中下标为3的地址 -> *一下则是p[3]的值, 也就是n4的地址 -> *n4的地址 则是n4的值
*/
}
void t3() {
int myInt[4] = {1, 2, 3, 4};
int Length = sizeof(myInt) / sizeof(int);
int(*p)[4] = myInt;
for (int i = 0; i < Length; i++) {
printf("\n%d", *((*p)+i)); // 1 2 3 4
printf("\n%d", (*p)[i]); // 1 2 3 4
}
}
int* t4() {
static int n3 = 10;
return &n3; // 注意, 这里必须返回 static 的内容
// 在 main() 函数中执行 printf("%d", *t4()); 打印 10
}
void t5(void) {
printf("Hello, World");
// 在main中 int (*p)(void) = t5; p(); 则打印 Hello, World
}
void main() {
t1();
}
指针与指针之间四则运算, 只允许减法
# include <stdio.h>
void main(){
int DATA[2] = {1, 2};
int* p1 = DATA;
int* p2 = &DATA[1];
printf("%p - %p = %p = %p", &p1, &p2, p1 - p2, p2 - p1);
printf("%p + %p = %p = %p", &p1, &p2, p1 + p2, p2 + p1); // error: invalid operands to binary + (have 'int *' and 'int *')
getchar();
}
二维数组指针问题
# include <stdio.h>
void main(){
int a[3][4] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}, *p1 = *(a[1]+1), *p2 = *(&a[1][1]), *p3 = ((*(a+1))[1]), *p4 = *(a+0);
printf("%d %d %d %d", p1, p2, p3, p4);
// p4 选择了 二维数组的第一行
getchar();
}
避免与指针操作混淆:
# include <stdio.h>
void main(){
int a[2][2] = {
{1, 2},
{3, 4}
};
int *p = a;
printf("Arr: %p + 1 = %p", a, a + 1); // 加了 2 个 int 单位
printf("\np: %p + 1 = %p", p, p + 1); // 加了 1 个 int 单位, 指针并不知道是数组还是值
getchar();
}
字符串数组问题
# include <stdio.h>
void main(){
char S[6] = {'A', 'B', 'C', 'D', 'E'}; // 不会溢出, 因为数组一旦被赋值, 多余的位变0
printf("%s", S);
getchar();
getchar();
}
# include <stdio.h>
void main(){
char * S = {'0'}; // 语法错误, 指针不允许直接赋值数组
printf("%s", S);
getchar();
getchar();
}
二维数组的本质
二维数组用函数接收
# include <stdio.h>
# include <math.h>
# define N 4
int fun(int p[][N]){ // 这种写法也可以, 最后一维必须有值
return 1;
}
fun2(int *p[N]){ // 这种写法也可以, 默认返回int
return 2;
}
void main(){
int b[N][N], x;
int a = fun(b);
fun2(b);
getchar();
getchar();
}
字符串在内存中存放的值
函数原型声明
结构体未初始化全面
# include <stdio.h>
struct Person {
char name[20];
int age;
} p1 = {"ZhangSan"};
void main(){
printf("%d", p1.age); // 默认是0
getchar();
getchar();
}
scanf & printf 问题
不可以使用 scanf 给 char * 赋值
在接收键盘字符时, 我们只能给char Str[值];
数组形式赋值, 不可以给char * Str
赋值, 因为指针是两层的, 永远指向一个地址.
注意, 图中的[30]
不可以省略为[]
, 想要省略必须在一行语句中初始化该变量才行, 例如:
int test[] = {1, 2, 3};
scanf %s吃scanf中的字符问题
让%s停止的只有 \n \t 等. B选项想完成,分割的目的要用 %2s, 限制一下字符串的长度.
scanf要求数字长度
答案: B
scanf %c吃\n问题
# include <stdio.h>
# include <math.h>
void main(){
// 测试1: %d 和 %c
// 要求: a存入30, c存入字符b
// int a; char c;
// scanf("%d%c", &a, &c); // %c当遇到<回车>时, 会将\n吃入 这里只能输入 30b
// scanf("%c%d", &c, &a); // %c只吃一个字符, 所以可以输入b30, 而且 %d 不会吃入 \n 所以还可以写入 b<回车>30
// printf("%d %c", a, c);
// 测试2: %d 和 %lf
// 要求: a存入30, b存入30
// int a; double b;
// scanf("%d%lf", &a, &b); // 数字遇到数字, 只能通过 30<回车>30 来进行读入
// printf("%d %f", a, b);
// 测试3: %d 和 %s
// 要求: 存入123 和 abc
int a; char b[20];
scanf("%d%s", &a, b); // %s 不吃\n, 所以这里可以写入123<回车>abc 或 123abc
printf("%d %s", a, b);
getchar();
getchar();
}
printf 左侧右侧补空格问题 (百分号是左撇子)
数组指针真实案例
# include <stdio.h>
void main(){
// 指针数组理解
int a = 10;
int b = 20;
int *ptr[2];
ptr[0] = &a;
ptr[1] = &b;
*ptr[0] = 100;
*ptr[1] = 200;
printf("%d %d\n", a, b);
/*
结果: 100 200
内存布局
ptr
0x00 指针1 -> a地址
0x00 指针2 -> b地址
*/
// 数组指针理解
int OneArr[5] = {1, 2, 3, 4, 5};
int (*p1)[5] = &OneArr; // 不要再指向首地址了, 指向整个数组的地址.
for(int i = 0; i < 5; i ++){
printf("%d ", *(*p1 + i));
}
printf("\n");
/*
结果: 1 2 3 4 5
内存布局:
p1 是一个指针, 指向了包含五个元素的数组
*p1 : 找到了这个数组, 数组的首地址找到了
(*p1)[i] : 数组首地址[下标] 访问到了指定元素
*(*p1) : 找到了这个的首地址, 继续*, 则找到了首地址的值
*(*p1 + i) : *(首地址 + i)
*/
// 二维数组指针理解
int TwoArr[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
int (*p2)[3] = TwoArr; // 直接指向了数组第一行
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j ++){
printf("%d ", (*p2)[j]);
}
printf("\n");
}
/*
结果:
1 2 3
4 5 6
内存布局:
p2 是一个指针, 指向了一个数组的第一行.
*p2 : 找到了这个数组的第1行第1个数的地址
**p2 : 找到了这个数组的第1行第1个数的值
(*p2)[j] : 找到了第1行, 通过选择, 选择到了第1行第j列
*(p2 + i) : 找到了这个数组第 i 行的地址第1个数的地址, 为什么能选择行?因为有定义[3], 加一次则加3*i, 自然选到第二行
*(*(p2+i) + j) : 找到了这个数组第 i 行的地址第j个数的值
*/
getchar();
}
类似数组指针的题目
正确答案是C, 原理与数组指针的本质特别相似.
易错点
二维数组, +n等于+n列, 例如 a+1, 则选到了第二列. 但是一维数组+n等于往后+n.
++ 本质
ax = 10;
ax = ax ++;
MOV AX, 10
PUSH AX
INC AX
POP AX
// 看似是 b = a++; 是先把 a 的内容给b
// 其实是 先把 a 入栈, 然后a自增, 然后再出栈给 b
// ++a 正常理解即可
; 升级版本
void main(){
int a = 1;
int b = 1;
a = b++ + a ++; // 结果2, 自增仍然失效. 四则中看见 a = a++类型, 不要想着a++自增.
printf("%d", a);
getchar();
getchar();
}
++与三元混淆题目
看似是一条语句, 实际上是三条语句.
程序设计题
// 编程序:在主函数中输入 10 个等长的字符串,子函数对它们排序,最后在主函数中输出排好序的字符串。
// 自己编写 strcmp 函数, 用 mystrcmp
# include <stdio.h>
# include <string.h>
# define N 3
void printArr(char Strs[3][5]){
for(int i = 0; i < N; i ++){
printf("%s, ", Strs[i]);
}
}
int myStrcmp(char * s1, char * s2){
while(*s1++ == *s2++);
return *s1 == '\0' ? 0 : (*s1 > *s2 ? 1 : -1);
}
void main(){
char Strs[3][5]; // 字符串长度是4
for(int i = 0; i < N; i ++){ // 得到所有字符串
printf("请输入第 %d 个字符串 (长度是4): ", i + 1);
scanf("%s", Strs[i]);
}
for(int i = 0; i < N - 1; i++){
for(int j = 0; j < N - 1 - i; j++){
if(myStrcmp(Strs[j], Strs[j + 1]) > 0){
for(int k = 0; k < 5; k++){
int c1 = Strs[j][k];
Strs[j][k] = Strs[j + 1][k];
Strs[j + 1][k] = c1;
}
}
}
}
printArr(Strs);
getchar();
getchar();
}
# include <stdio.h>
# include <math.h>
// 最大公约数, 最小公倍数
void fun(int MAX, int MIN){
int temp, x; // temp: 临时变量 x: 最小公倍数
// 最大公约数, 最小公倍数模板
/*
MAX MIN
24 15 -> 24%15=9
15 9 -> 15%9=6
9 6 -> 9%6=3
6 3 -> 6%3=0
3 0 -> 最大公约数是3
最小公倍数公式: MAX*MIN / 他俩的最大公约数
*/
if(MAX < MIN){ // 把最大的数给 MAX
temp = MAX;
MAX = MIN;
MIN = temp;
}
x = MAX * MIN;
while(MIN > 0){
temp = MAX % MIN;
MAX = MIN;
MIN = temp; // 最大公约数算法
}
x /= MAX; // 最小公倍数
printf("最大公约数: %d, 最小公倍数: %d", MAX, x);
}
void main() {
/* 99乘法表 */
/*
for (int i = 1; i <= 9; i ++) {
for (int j = 1; j <= i; j ++) {
printf("%d * %d = %d ", j, i, i * j);
}
printf("\n");
}
*/
/*金字塔*/
// 金字塔1
/*
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= i; j ++) {
printf("*");
}
printf("\n");
}
*/
// 金字塔2
/*
for (int i = 1; i <= 6; i++) {
// 打印空格
for (int j = 1; j <= 6 - i; j ++) {
printf(" ");
}
// 打印星号
for (int k = 1; k <= 2 * i - 1; k ++) {
printf("*");
}
printf("\n");
}
*/
// 金字塔3
/*
for (int i = 1; i <= 9; i ++) {
// 打印空格
for (int j = 1; j <= 9 - i; j ++) {
printf(" ");
}
for (int k = 1; k <= 2 * i - 1; k ++) {
printf("*");
}
printf("\n");
}
*/
// 空心菱形
/*for (int i = 1; i <= 5; i ++) {
for (int j = 1; j <= 5 - i;j++) {
printf(" ");
}
for (int k = 1; k <= 2 * i - 1;k ++) {
if (k == 1 || k == 2 * i - 1) {
printf("*");
}
else {
printf(" ");
}
}
printf("\n");
}
for (int i = 4; i >= 1; i--) {
for (int k = 1; k <= 5 - i; k ++) {
printf(" ");
}
for (int j = 1; j <= 2 * i - 1; j ++) {
if (j == 1 || j == 2 * i - 1) {
printf("*");
}
else {
printf(" ");
}
}
printf("\n");
}*/
// 斐波那契数
/* 递归函数
int fbn(int num) {
if (num == 1 || num == 2) {
return 1;
}
else {
return fbn(num-1) + fbn(num-2);
}
}
*/
/* for 循环完成
int f1 = 1, f2 = 1, f;
for (int i = 3; i <= 7; i++) {
f = f1 + f2;
f1 = f2;
f2 = f;
}
printf("%d, %d", f, fbn(7));
*/
// 有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃
// 其中的一半,然后再多吃一个。当到第十天时,想再吃时(还没吃),发现只有
// 1个桃子了。问题:最初共多少个桃子?
/*
int taozi(int day) {
if (day == 10) {
return 1;
}
else {
return (taozi(day + 1) + 1)*2;
}
}
*/
// 判断素数 (素数是只能被1以及本身整除的数)
/*int isprime(int x) {
for (int i = 2; i < x; i++) {
if (x % i == 0) {
// 不是素数
return 0;
}
}
return 1; // 是素数
}*/
# include <stdio.h>
// 用递归的方法将一个整数n转换成字符串, 例如: 输入1234, 应输出字符串 "1234". n的位数不确定, 可以是任意位数的整数.
void Converter(int nums) {
int n = nums; // 除 10 判断上面是否还有内容
if ((n = n / 10) != 0) Converter(n);
putchar(nums % 10 + '0'); // 余 10 得到最后一位
}
void main() {
int nums;
printf("请输入数字: ");
scanf("%d", &nums);
Converter(nums);
}
}
字符串的四种操作
# include <stdio.h>
void main(){
// 串连接
// 数组
// char s1[30] = "Hello", s2[30] = "World";
// int i = 0, j = 0;
// while(s1[i]) i++; // i到 \0 位置
// while(s1[i++] = s2[j++]);
// printf("%s", s1);
// 指针
// char s1[30] = "Hello", s2[30] = "World";
// char *p = s1, *q = s2;
// while(*p) p++; // i到 \0 位置
// while(*p++ = *q++);
// printf("%s", s1);
// 串求长
// 数组
// char s1[] = "HelloWorld";
// int i = 0;
// while(s1[i]) i++;
// printf("%d", i);
// 指针
// char s1[] = "HelloWorld";
// char *p = s1;
// while(*p++);
// printf("%d", p-1-s1);
// 串拷贝
// char s1[30] = "HelloHacker", s2[30] = "World";
// int i = 0, j = 0;
// while(s1[i++] = s2[j++]);
// printf("%s", s1);
// 串删除某一字符串
char s1[30] = "HelloHacker", s = 'l', *q = s1, *p;
while(*q){
if(*q == s){
p = q;
while(*p){
*p = *(p+1);
p++;
}
*p = '\0';
continue;
}
q++;
}
printf("%s", s1);
getchar();
}
ABCD 变为 BCDA
# include <stdio.h>
// 字符串逆序
void main(){
char ch[20] = "ABCDEF", *p1 = ch, *p2 = ch, c;
while(*p2++ != '\0');
p2 -= 2;
while(p2 > p1){
c = *p2;
*p2 = *p1;
*p1 = c;
p2--;
p1++;
}
printf("%s", ch);
getchar();
}
找最大值
# include "stdio.h"
int main(){
int a = 10, b = 20, c = 50;
int max = 0;
// if 比较法
// if(a > b){
// max = a;
// }else{
// max = b;
// }
// if(max < c){
// max = c;
// }
// 三元运算符比较法
int data = a > b ? (b > c ? b : c) : (b > c ? b : c) ;
printf("%d", data);
getchar();
getchar();
getchar();
getchar();
return 0;
}
公式题
# include "stdio.h"
# include "math.h"
int main(){
int a, b, c;
double Gen, x1, x2;
scanf("%d%d%d", &a, &b, &c);
if(a == 0){
printf("a不能是0!");
return 0;
}
Gen = sqrt(b * b - 4 * a * c);
if(Gen >= 0){
x1 = (-b + Gen) / (2 * a);
x2 = (-b - Gen) / (2 * a);
printf("方程的两个根分别为: %f %f", x1, x2);
}else{
printf("方程无根!");
}
getchar();
getchar();
getchar();
getchar();
return 0;
}
分子分母题
以后初始化用do{}while(); 不用图中的案例. 会少加一位.
结构体地址加箭头的写法 (用指针也可以实现)
进制转换 (包括微机原理)
# include <stdio.h>
# include <math.h>
# define N 20
int myZhuanHuan(int Num, int Now, int Dist){
if(Now == 10 && Dist != 10){
// 顺进制: 对目标进制取余 余数倒排
int Result[N], i = 0, j = 0;
int NumRes = 0;
while(Num > 0){
Result[i++] = Num % Dist;
Num /= Dist;
}
for(j = i-1; j >= 0; j--){
NumRes = NumRes * Now + Result[j];
}
return NumRes;
}else if(Now != 10 && Dist == 10){
// 逆进制: 余目标进制取位 乘当前进制的N次方 相乘后相加在一起
int Result = 0;
int Index = 0;
while(Num > 0){
int NowDist = 1;
for(int i = 0; i < Index; i++){
NowDist = NowDist * Now;
}
Result += (Num % Dist) * NowDist;
Num /= Dist;
Index ++;
}
return Result;
}else{
return myZhuanHuan(myZhuanHuan(Num, Now, 10), 10, Dist);
}
}
void main(){
// 题目1: 要求将八进制521转化为十进制数
/*
思路: C语言默认为10进制为1组, 所以
"10进制" -> "其他进制" : 除 "其他进制" 取余法
"其他进制" -> "10进制" : 位置加权法 (加权的是其他进制)
微机原理中: 默认16进制为一组, 所以
"16进制" -> "其他进制" : 除 "其他进制" 取余法
"其他进制" -> "16进制" : 位置加权法 (加权的是其他进制)
总结: 顺进制 -> 对目标进制取余 余数倒排
逆进制 -> 对目标进制取余 乘当前进制的N次方 相加在一起
*/
// int myOct = 521;
// int myResult = 0;
// int myIndex = 0;
// while(myOct > 0){
// int Temp = myOct % 10; // 目的进制取位
// int Temp2 = 1;
// for(int i = 0; i < myIndex; i++){
// Temp2 *= 8; // 乘当前进制权
// }
// myResult += Temp * Temp2;
// myOct /= 10;
// myIndex ++;
// }
// printf("%d", myResult);
printf("%d", myZhuanHuan(32, 8, 16));
getchar();
getchar();
}
凯撒密码
A变成Z, B变成Y的算法
后面使用了未定义的值, 这种情况while中必然有赋值操作!!!
斐波那契数
# include <stdio.h>
# include <math.h>
void main(){
// 斐波那契数列累加
int f1 = 1, f2 = 1, f, i, sum = 0;
sum += f1 + f2;
for(i = 3; i <= 20; i++){
f = f1 + f2;
sum += f;
f1 = f2;
f2 = f;
}
printf("%d", sum);
getchar();
getchar();
}
接收键盘字符骚操作
getchar() 循环 (因为scanf不会接收空格)
# include <stdio.h>
void main(){
char myStrs[30];
int i = 0;
while((myStrs[i] = getchar()) != '\n'){ // \n的时候停止
// 判断逻辑...运行逻辑...
}
getchar();
}
scanf() 循环 (因为getchar接收的都是ASCII码)
# include <stdio.h>
# include <math.h>
void main(){
int num;
scanf("%d", &num);
while(num >= 1 && num <= 13){ // 何时退出
// 判断逻辑...
scanf("%d", &num);
}
getchar();
getchar();
}