C语言快速入门-C语言基础知识
这个c语言入门,目标人群是有代码基础的,例如你之前学过javaSE,看此文章可能是更有帮助,会让你快速掌握他们之间的差异,文章内容大部分都是泛谈,详细的部分我会在之后时间发布,我也在慢慢学习,勉励同志们。
随后时间我会发布C语言详细(进阶版),数据结构,C++等的文章,喜欢的可以一起讨论。
目录
一. 第一个c语言程序(输出hello)
(1)VC Code输出
(2)Windows 终端 输出(有乱码不碍事)
二. 数据类型
1. 七个数据类型
2. 数据类型的长度
3. 数据类型的使用(举例)
三. 变量、常量
1.1. 定义变量
1.2. 变量的分类
1.3. 变量的使用
1.4. 变量的作用域与生命周期
2. 定量 / 常量
2.1 常量定义
2.2 常量类型
四. 字符串+转义字符+注释+格式修饰符
1. 字符串
2. 转义字符
3. 注释
4. 格式说明符
五. 选择语句
六. 循环语句
1. 循环类型
2. 代码示例
3. 循环控制语句(break/continue)
4. 运算符(符合运算符)此处不太明白,日后加强联系。
七. 函数
1.函数定义
2.函数代码示例
八. 数组
1. 数组的类型
2. 数组的下标
3. 数组的使用(遍历)
3.1.常规数组的使用与遍历
(1). 常规遍历-正序
(2). 常规遍历-倒叙
3.2. 二维数组的使用与(嵌套遍历)
3.3. 字符串数组与字符串的使用与遍历
3.4. 指针数组的使用与遍历
3.5. 动态数组(堆内存)的使用与遍历
4. 数组的整体代码
九. 操作符
十. 常见关键字
十一. define 定义常量和宏
关键注释说明
宏 vs 常量变量
代码示例:
十二. 指针(泛谈)
1. 什么是指针?
2. 指针操作解析表
3. 代码示例
4. 总结
指针的核心概念总结
5. 最佳实践建议
十三. 结构体(泛谈)
1. 什么是结构体?
2. 结构体操作解析表
3. 代码示例
4. 总结
5. 最佳实践建议
一. 第一个c语言程序(输出hello)
#include <stdio.h>//相当于import java中的导包,包中包含着很多你需要使用的函数等
//main就是主函数,运行程序的入口,有且必须只有一个。
int main() {printf("hello,world\n"); //输出语句,\n表示换行printf("哈啊哈\n");return 0;//因为主函数的数据类型为int,所以,返回值为int,其余同理,viod则空
}
输出:
(1)VC Code输出
(2)Windows 终端 输出(有乱码不碍事)
(Linux输出其实也差不多)
二. 数据类型
1. 七个数据类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
C语言中没有String字符串类型吗????
c语言中string用char的数组形式来表示。下方代码有举例。
2. 数据类型的长度
3. 数据类型的使用(举例)
#include <stdio.h>int main() {char a = 'a'; // 字符型变量 achar a1[] = {'h', 'e', 'l', 'l', 'o', '\0'}; // 字符型数组 a1,注意加上结束符 '\0'char str1[] = "Hello"; // 字符数组表示字符串,即java中的stringchar *str2 = "World"; // 字符指针表示字符串short b = 10; // 短整型变量 bint c = 10; // 整型变量 clong d = 10; // 长整型变量 dfloat f = 10.0f; // 单精度浮点数 fdouble g = 10.00000; // 双精度浮点数 g// 输出变量的值printf("字符 a: %c\n", a);printf("字符数组 a1: %s\n", a1);printf("%s %s\n", str1, str2); printf("Length of str1: %zu\n", strlen(str1));//输出str1的长度,即为5printf("短整型 b: %d\n", b);printf("整型 c: %d\n", c);printf("长整型 d: %ld\n", d);printf("单精度浮点数 f: %.2f\n", f);printf("双精度浮点数 g: %.5f\n", g);return 0;}
输出:
三. 变量、常量
1. 变量
1.1. 定义变量
简而言之变量即使可以更改的量,其数值可以被更改。
1.2. 变量的分类
1.全局变量
(1)即作用于代码运行全过程的变量
2.局部变量
(2)即作用于部分代码块的变量
#include <stdio.h>
// 全局变量
int globalVar = 10; // 全局变量,作用域为整个文件
void function() {// 局部变量int localVar = 5; // 局部变量,作用域仅限于此函数内printf(" 函数内 局部变量 localVar 的值: %d\n", localVar);printf(" 函数内 全局变量 globalVar 的值: %d\n", globalVar);
}int main() {printf("全局变量 globalVar 的值: %d\n", globalVar); // 可以访问全局变量function();//调用上方的函数// printf("局部变量 localVar 的值: %d\n", localVar); // 这行代码会报错,因为 localVar 作用域仅限于 function 函数return 0;
}
1.3. 变量的使用
使变量等于输入两个值,使这两个变量进行加减乘除,结果取小数点后两位。
#include <stdio.h>
int main() {// 定义变量float num1, num2; // 用于存储输入的两个数float sum, difference, product, quotient; // 用于存储运算结果// 提示用户输入两个数,scanf的标准用法,于printf很相似printf("请输入第一个数: ");scanf("%f", &num1); // 读取第一个数printf("请输入第二个数: ");scanf("%f", &num2); // 读取第二个数// 进行运算sum = num1 + num2; // 加法difference = num1 - num2; // 减法product = num1 * num2; // 乘法quotient = num1 / num2; // 除法(注意:需要确保 num2 不为 0)// 输出结果,%.2f即为取余,小数点后两位,%.3f即为小数点后3位,以此类推。printf("加法结果: %.3f\n", sum);printf("减法结果: %.3f\n", difference);printf("乘法结果: %.3f\n", product);// 除法结果的输出需要检查除数是否为0if (num2 != 0) {printf("除法结果: %.2f\n", quotient);} else {printf("除法结果: 无法除以零\n");}return 0;
}
输出:
1.4. 变量的作用域与生命周期
作用域:
作用域( scope )是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是 可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。1. 局部变量的作用域是变量所在的局部范围。2. 全局变量的作用域是整个代码运行过程。
生命周期:
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。2. 全局变量的生命周期是:整个程序的生命周期,同理。
2. 定量 / 常量
2.1 常量定义
简而言之,定量即使不变的量。
2.2 常量类型
1. 字面常量2. const 修饰的常变量(java中常用)3. #define 定义的标识符常量4. 枚举常量
#include <stdio.h>// 使用 #define 定义标识符常量
#define PI 3.14159 // 圆周率常量// 定义枚举常量
enum Color {RED, // 默认第一个为0,以此类推。GREEN, // GREEN = 1BLUE // BLUE = 2
};int main() {// 字面常量int a = 10; // 整数字面常量float b = 5.5; // 浮点数字面常量// const 修饰的常量const int MAX_VALUE = 100; // 最大值常量,不能被修改// 输出各个常量的值printf("字面常量 a: %d\n", a);printf("字面常量 b: %.2f\n", b);printf("标识符常量 PI: %.5f\n", PI);printf("const 常量 MAX_VALUE: %d\n", MAX_VALUE);// 使用枚举常量enum Color myColor = GREEN; // 赋值为枚举常量printf("枚举常量 myColor: %d\n", myColor); // 输出枚举常量的整数值return 0;
}
输出
四. 字符串+转义字符+注释+格式修饰符
1. 字符串
1. 即Java中的String,用来表示多个字符在一起的样子。但是C中没有String的概念,所以字符串用char【】(字符型数组)来表示。
2. 下方的代码,用了四种方式来表示String,具体看代码注释,写的很清楚。
//可以简单认为include与java中的import是同一个意思。
#include <stdio.h> // 引入标准输入输出库,提供输入输出函数,如printf和scanf
#include <stdlib.h> // 引入标准库,包含内存分配(如malloc、free)、进程控制和转换等函数
#include <string.h> // 引入字符串处理库,提供字符串操作函数,如strcpy、strlen等int main() {// 1. 使用字符数组定义字符串char str1[] = "hello world"; // 字符数组,自动添加'\0'char str11[] ={'0','1','2','3','4','\0'}; // 字符数组,自动添加'\0'<规范>// 2. 使用字符指针定义字符串const char *str2 = "hello world"; // 字符指针指向字符串常量// 3. 动态内存分配,malloc 返回的是 void* 类型的指针,表示它可以指向任何类型的内存。//指针相当于一种特殊类型的变量char *str3 = (char *)malloc(12 * sizeof(char)); // 开辟一个char类型,12长度的内存空间变量为str3这个指针变量if (str3 == NULL) { // 检查内存是否分配存在printf("内存分配失败\n");return 1; // 返回1表示异常,并输出内存分配失败}strcpy(str3, "hello world"); // // 输出所有字符串printf("%s\n", str1); // 输出字符数组printf("%s\n", str11); // 输出字符数组printf("%s\n", str2); // 输出字符指针printf("%s\n", str3); // 输出动态分配的字符串// 释放动态分配的内存free(str3);return 0; // 返回0表示程序正常结束
}
输出:
2. 转义字符
转义字符 释义(转义字符顾名思义就是转变意思。)\? 在书写连续多个问号时使用,防止他们被解析成三字母词\' 用于表示字符常量'\" 用于表示一个字符串内部的双引号\\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。\a 警告字符,蜂鸣\b 退格符\f 进纸符\n 换行\r 回车\t 水平制表符\v 垂直制表符\ddd ddd表示 1~3 个八进制的数字。 如: \130 X\xdd dd表示 2 个十六进制数字。 如: \x30 0
举例:
仔细看注释。
#include<stdio.h>
#include<string.h>
// strlen - string length - 求字符串长度
int main()
{printf("%d\n", strlen("abcdef"));printf("%d\n", strlen("abcdefg")); // 输出字符串 "abcdef" 的长度// \62被解析成一个转义字符printf("%d\n", strlen("c:\test\628\test.c"));//会输出错误,因为系统编译会把\t认识为转义符printf("%d\n", strlen("c:\\test\\628\\test.c")); // 使用双反斜杠表示反斜杠,就没有问题了。return 0;
}
详细使用方法:
#include <stdio.h>int main() {// 1. \? - 表示问号字符 原因: \? 不会被解析为转义字符,直接输出问号。 printf("这是一个问号: \?\n"); // 输出: 这是一个问号: ?// 2. \' - 表示单引号字符 原因: \' 被解析为单引号字符,用于在字符串中包含单引号。printf("这是一个单引号: \'\n"); // 输出: 这是一个单引号: '// 3. \" - 表示双引号字符 原因: \" 被解析为双引号字符,用于在字符串中包含双引号。printf("这是一个双引号: \"\n"); // 输出: 这是一个双引号: "// 4. \\ - 表示反斜杠字符 原因: \\ 被解析为一个反斜杠字符,用于在字符串中包含反斜杠。printf("这是一个反斜杠: \\\n"); // 输出: 这是一个反斜杠: \// 5. \a - 表示警告音(响铃)原因: \a 表示响铃字符,某些终端或系统可能会发出声音。printf("这将响铃: \a\n"); // 可能会发出警告音(依赖于终端设置)// 6. \b - 表示退格符 原因: \b 将光标移动到前一个字符位置,覆盖该字符。printf("这是一个退格符: Hello\bWorld\n"); // 输出: HelloWorld(“Hello”中的最后一个字母被删除)// // 7. \f - 表示换页符 原因: \f 在某些终端中可能会导致换页,但在其他终端中可能没有明显效果。printf("这是一个换页符: Hello\fWorld\n"); // 输出: Hello(在某些终端中可能表现为换页)// 8. \n - 表示换行符 原因: \n 将光标移动到下一行,输出内容在新行显示。printf("这是一个换行符: Hello\nWorld\n"); // 输出: Hello// // World// 9. \r - 表示回车符 原因: \r 将光标移动到行首,后续字符会覆盖当前行的内容。printf("这是一个回车符: Hello\rWorld\n"); // 输出: World(“Hello”被覆盖)// 10. \t - 表示水平制表符 原因: \t 插入一个水平制表符的空格,增加字符之间的间距。printf("这是一个制表符: Hello\tWorld\n"); // 输出: Hello World(“Hello”和“World”之间有一个制表符的空格)// 11. \v - 表示垂直制表符 原因: \v 在某些终端中可能表现为换行,但在其他终端中可能没有明显效果printf("这是一个垂直制表符: Hello\vWorld\n"); // 输出: Hello(可能会在某些终端中表现为换行)// 12. \ddd - 表示八进制数对应的字符 原因: 八进制数表示的字符在ASCII表中对应的字符。printf("这是一个八进制字符: \101\n"); // 输出: A(八进制101对应的字符是'A')// 13. \xdd - 表示十六进制数对应的字符 原因: 十六进制数表示的字符在ASCII表中对应的字符。printf("这是一个十六进制字符: \x41\n"); // 输出: A(十六进制41对应的字符是'A')return 0;}}}
3. 注释
1. 代码中有不需要的代码可以直接删除,也可以注释掉2. 代码中有些代码比较难懂,可以加一下注释文字
vs Code 分为单行注释与多行注释,自己搜索,默认的我也忘了。嘿嘿嘿。
4. 格式说明符
格式说明符:
%d 或 %i 解释:输出或输入有符号十进制整数。
%u 解释:输出或输入无符号十进制整数。
%f 解释:输出或输入十进制浮点数(float)。
%lf 解释:输出或输入双精度浮点数(double)。
%c 解释:输出或输入单个字符。
%s 解释:输出或输入字符串(字符数组)。
%p 解释:输出指针的地址(内存地址)。
%o 解释:输出无符号八进制整数。
%x 或 %X 解释:输出无符号十六进制整数。%x 使用小写字母,%X 使用大写字母。
%e 或 %E 解释:以科学计数法输出浮点数。%e 使用小写字母 e,%E 使用大写字母 E。
%g 或 %G 解释:根据数值的大小自动选择使用 %f 或 %e 的格式输出浮点数。%g 使用小写字母,
%G 解释:使用大写字母。
格式说明符代码解释 :
#include <stdio.h>
int main() {// 1. %d 或 %i - 输出或输入有符号十进制整数 // 原因: %d 用于打印有符号整数,负数会正常显示。int signedInt = -42;printf("有符号十进制整数: %d\n", signedInt); // 输出: 有符号十进制整数: -42// 2. %u - 输出或输入无符号十进制整数 // 原因: %u 用于打印无符号整数,确保不会显示负号。unsigned int unsignedInt = 42;printf("无符号十进制整数: %u\n", unsignedInt); // 输出: 无符号十进制整数: 42// 3. %f - 输出或输入十进制浮点数(float) // 原因: %f 默认输出六位小数,适用于浮点数。float floatNum = 3.14f;printf("十进制浮点数: %f\n", floatNum); // 输出: 十进制浮点数: 3.140000// 4. %lf - 输出或输入双精度浮点数(double) // 原因: %lf 用于打印双精度浮点数,默认输出六位小数。double doubleNum = 3.141592653589793;printf("双精度浮点数: %lf\n", doubleNum); // 输出: 双精度浮点数: 3.141593// 5. %c - 输出或输入单个字符 // 原因: %c 用于打印单个字符。char character = 'A';printf("单个字符: %c\n", character); // 输出: 单个字符: A// 6. %s - 输出或输入字符串(字符数组) // 原因: %s 用于打印字符串,直到遇到空字符 '\0'。char str[] = "Hello, World!";printf("字符串: %s\n", str); // 输出: 字符串: Hello, World!// 7. %p - 输出指针的地址(内存地址) // 原因: %p 用于打印指针的地址,通常以十六进制格式输出。int *ptr = &signedInt;printf("指针地址: %p\n", (void *)ptr); // 输出: 指针地址: 0x7ffeedc3a5b4(地址会因运行而异)// 8. %o - 输出无符号八进制整数 // 原因: %o 用于打印无符号整数的八进制表示。printf("无符号八进制整数: %o\n", unsignedInt); // 输出: 无符号八进制整数: 50// 9. %x 或 %X - 输出无符号十六进制整数 // 原因: %x 用于打印小写十六进制,%X 用于打印大写十六进制。printf("无符号十六进制整数 (小写): %x\n", unsignedInt); // 输出: 无符号十六进制整数 (小写): 2aprintf("无符号十六进制整数 (大写): %X\n", unsignedInt); // 输出: 无符号十六进制整数 (大写): 2A// 10. %e 或 %E - 以科学计数法输出浮点数 // 原因: %e 和 %E 用于以科学计数法格式打印浮点数。printf("科学计数法 (小写): %e\n", floatNum); // 输出: 科学计数法 (小写): 3.140000e+00printf("科学计数法 (大写): %E\n", floatNum); // 输出: 科学计数法 (大写): 3.140000E+00// 11. %g 或 %G - 根据数值的大小自动选择格式输出浮点数 // 原因: %g 和 %G 根据数值的大小选择使用 %f 或 %e 格式输出。printf("自动选择格式 (小写): %g\n", doubleNum); // 输出: 自动选择格式 (小写): 3.14159printf("自动选择格式 (大写): %G\n", doubleNum); // 输出: 自动选择格式 (大写): 3.14159return 0;
}
五. 选择语句
语句类型 适用场景 特点 if
单条件判断 无默认分支 if-else
二选一逻辑 必须选择其一 if-else if-else
多条件阶梯判断 按顺序检查条件 switch-case
离散值匹配(如枚举、字符) 效率高,需 break
防止穿透
输出
由于我坚信大家能看得懂,所以就不在此过多赘述!!
#include <stdio.h>int main() {//设置一些基础的变量。int score = 85;char grade = 'B';int num = 10;/* 1. 基础if语句:单条件判断 */if (score >= 60) {printf("1. 及格\n"); // 条件成立时执行}/* 2. if-else语句:二选一分支 */if (num % 2 == 0) {printf("2. 偶数\n");} else {printf("2. 奇数\n"); // 条件不成立时执行}/* 3. if-else if-else:多条件阶梯判断 */if (score >= 90) {printf("3. 优秀\n");} else if (score >= 80) {printf("3. 良好\n"); // 满足 score>=80 但 score<90} else if (score >= 60) {printf("3. 及格\n");} else {printf("3. 不及格\n"); // 默认分支}/* 4. switch-case:离散值匹配 */switch (grade) {case 'A': printf("4. 90-100分\n");break; // 必须用break阻止穿透case 'B':printf("4. 80-89分\n");break;case 'C':printf("4. 60-79分\n");break;default:printf("4. 不及格\n"); // 默认分支}return 0;
}
六. 循环语句
1. 循环类型
循环类型 执行顺序 适用场景 注意事项 for
先检查后执行 明确循环次数(如数组遍历) 循环变量作用域需注意 while
先检查后执行 条件未知但需前置检查(如读文件) 避免忘记更新条件变量导致死循环 do-while
先执行后检查 至少执行一次(如用户输入验证) 结尾分号不可遗漏
2. 代码示例
#include <stdio.h>int main() {/* 示例1: for循环(明确循环次数) */for (int i = 1; i <= 3; i++) {printf(" 第%d次循环\n", i); // 循环体执行3次}/* 示例2: while循环(条件驱动循环) */int count = 3;while (count > 0) {printf(" 剩余次数: %d\n", count);count--; // 修改条件变量避免死循环}/* 示例3: do-while循环(至少执行一次) */int input;do {printf(" 输入1继续,其他退出: ");scanf("%d", &input);} while (input >=1); // 先执行后判断/* 示例4: 循环控制语句(break/continue) */for (int j = 1; j <= 6; j++) {if (j == 3) {continue; // 跳过本次循环剩余代码,当j==3的时候,跳出本次循环,执行j==4,即输出语句不含有3。}if (j == 6) {break; // 提前终止整个循环,当j==6的时候,终止循环,即输出语句不含有6,及其以下语句。}printf(" 当前值: %d\n", j);}return 0;
}
输出:
3. 循环控制语句(break/continue)
语句 作用 示例场景 break
立即终止当前循环 搜索到目标后提前退出循环 continue
跳过本次循环剩余代码,进入下一轮循环 过滤无效数据(如跳过负数处理)
4. 运算符(符合运算符)此处不太明白,日后加强联系。
运算符 行为描述 典型应用场景 示例 结果 i++
先用后加(后缀自增) 循环变量更新 int i = 5; int j = i++; j = 5,然后 i 变成 6++i
先加后用(前缀自增) 需要立即使用新值 int i = 5; int j = ++i; i 先变成 6,然后 j = 6i--
先用后减(后缀自减) 递减计数器 int i = 5; int j = i--; j = 5,i = 4--i
先减后用(前缀自减) 需要立即使用新值
int i = 5;
int j = i--;
i = 3,k = 3
运算符 含义 示例 等价表达式 +=
加法赋值 a += 5
a = a + 5
-=
减法赋值 a -= 3
a = a - 3
*=
乘法赋值 a *= 2
a = a * 2
/=
除法赋值 a /= 4
a = a / 4
%=
取模赋值 a %= 3
a = a % 3
&=
按位与赋值 a &= 0x0F
a = a & 0x0F
^=
按位异或赋值 a ^= b
a = a ^ b
<<=
左移赋值 a <<= 2
a = a << 2
>>=
右移赋值 a >>= 1
a = a >> 1
输出:
#include <stdio.h>int main() {int a = 10, b = 3, c = 5;/* 1. 基本运算符 */// 算术运算符printf("a + b = %d\n", a + b); // 加法:13printf("a %% b = %d\n", a % b); // 取模:1(余数)// 关系运算符printf("a > b? %d\n", a > b); // 1(true)// 逻辑运算符printf("!(a < 5) = %d\n", !(a < 5)); // 1(非操作)// 位运算符printf("a & b = %d\n", a & b); // 按位与:2(1010 & 0011 = 0010)printf("a << 2 = %d\n", a << 2); // 左移2位:40// 赋值运算符c = a; // 基本赋值,c变为10// 条件运算符(三目运算符)int max = (a > b) ? a : b; // max=10// 逗号运算符int d = (a++, b++, a + b); // d=15(a=11, b=4)/* 2. 复合运算符(组合赋值) */a += 5; // 等价于 a = a + 5 → 15b *= 2; // 等价于 b = b * 2 → 8c &= 0x0F; // 等价于 c = c & 0x0F → 10的二进制高4位清零 → 10// 验证结果printf("a=%d, b=%d, c=%d, d=%d, max=%d\n", a, b, c, d, max);return 0;
}
七. 函数
1.函数定义
即为Java中的方法,目的是为了提高代码复用率,可用性。
2.函数代码示例
代码中包含了六个函数,各有差异。细节都在注释之中了,仔细看,不是很难,比较难理解的是指针类型定义,这个我会在c语言的进阶版详细来说。
#include <stdio.h>//1. 无返回值、无参数函数:用于执行特定任务,不返回数据,引用参数输出hello world 换行
void greet(void) {printf("Hello World!\n");
}// 2. 带参数和返回值的函数:接收两个整数,返回它们的和
int add(int a, int b) { // 参数是值传递(拷贝)return a + b;
}//3. 指针参数函数:通过地址修改外部变量 ,
void swap(int *x, int *y) { // 使用指针实现"引用传递"效果,a=10 , b=20,输出结果应改为 *x等于20,*y=10;int temp = *x;//*x的值传给temp =10;*x = *y ;//*y把值传给*x,此时*x的值为20*y = temp;//temp(10)的值传给*y,temp的值为10。
}// 4. 递归函数:计算阶乘,需设置终止条件
int factorial(int n) {if (n < 0) return -1; // 错误检查,简单选择语句,即 使参数n不得小于0return (n <= 1) ? 1 : n * factorial(n - 1);//三运运算符,若n=1则返回1,n>1,则 n * factorial(n - 1),即为递归函数
}/* 5. 函数指针类型定义:用于实现回调机制 */
typedef int (*MathOperation)(int, int); // 定义函数指针类型,/* 6. 函数原型声明:必须在使用前声明(定义可在后面) */
double divide(double a, double b); // 函数原型
/* 函数实现:除法运算 */
double divide(double a, double b) {if (b == 0) { // 参数有效性检查printf("错误:除数不能为0\n");return 0;}return a / b;
}int main() {// 1.调用无参函数greet(); // 2.调用函数a+b的结果,传参什么的,不过大多叙述。int result = add(3, 5); // 接收返回值printf("3 + 5 = %d\n", result);// 3.int a = 10, b = 20;printf("交换前:a=%d, b=%d\n", a, b);swap(&a, &b); // 传递地址修改实参printf("交换后:a=%d, b=%d\n", a, b);// 4. 输出结果即为 5*5-1printf("5的阶乘 = %d\n", factorial(5));//即给参数即可,算的是5的递归。//函数指针使用MathOperation operation = add; // 指向add函数,我能理解,即为定义指针函数,把add的作用调到operation中使用,可以简单理解。printf("函数指针运算:%d\n", operation(7, 8));//printf("10 / 3 = %.2f\n", divide(10.0, 3.0));return 0;
}
输出:
八. 数组
1. 数组的类型
1. 常规数组
2. 二维数组
3. 字符串数组与字符串
4. 指针数组
5. 动态数组(堆内存)
2. 数组的下标
此处的重点就是,记住下标第一个是0.
3. 数组的使用(遍历)
3.1.常规数组的使用与遍历
(1). 常规遍历-正序
// 2. 常规遍历(正序)printf("arr1元素:");for (int i = 0; i < 5; i++) {printf("%d ", arr1[i]); // 通过下标访问,输出:1 2 3 0 0}
(2). 常规遍历-倒叙
// 3. 逆序遍历printf("\narr2逆序:");for (int i = sizeof(arr2)/sizeof(arr2[0]) - 1; i >= 0; i--) {printf("%d ", arr2[i]); // 输出:30 20 10}
3.2. 二维数组的使用与(嵌套遍历)
int matrix[2][3] = {{1, 2, 3},{4, 5, 6}};printf("\n二维数组遍历:\n");for (int row = 0; row < 2; row++) {for (int col = 0; col < 3; col++) {printf("matrix[%d][%d]=%d ", row, col, matrix[row][col]);}printf("\n");}
3.3. 字符串数组与字符串的使用与遍历
char str1[] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 手动添加结束符char str2[] = "World"; // 自动添加结束符'\0',长度=5+1=6printf("字符串遍历:");int i = 0;while (str1[i] != '\0') { // 遍历到结束符停止printf("%c", str1[i++]); // 输出:Hello}printf(" %s\n", str2); // 直接输出:World------%s 解释:输出或输入字符串(字符数组)。
3.4. 指针数组的使用与遍历
const char *words[] = {"Apple", "Banana", "Cherry"}; // 字符串指针数组printf("指针数组元素:\n");for (int i = 0; i < 3; i++) {printf("第%d个单词: %s\n", i, words[i]); // 通过指针访问字符串}
3.5. 动态数组(堆内存)的使用与遍历
int *dynamic_arr = malloc(5 * sizeof(int)); // 动态分配5个int空间if (dynamic_arr == NULL) {printf("内存分配失败!");return 1;}// 初始化动态数组for (int i = 0; i < 5; i++) {dynamic_arr[i] = i * 10; // 下标访问与普通数组一致}// 指针遍历动态数组printf("动态数组:");int *ptr = dynamic_arr;for (int i = 0; i < 5; i++) {printf("%d ", *ptr++); // 输出:0 10 20 30 40}free(dynamic_arr); // 必须释放内存!
4. 数组的整体代码
#include <stdio.h>
#include <stdlib.h> // 用于动态数组int main() {/*=====================一维数组基础-----这个好理解。======================*/// 1. 定义与初始化int arr1[5] = {1, 2, 3}; // 长度为5,部分初始化,未赋值元素默认为0,即为剩下两个位置为0,0int arr2[] = {10, 20, 30}; // 自动推断长度(3个元素)// 2. 常规遍历(正序)printf("arr1元素:");for (int i = 0; i < 5; i++) {printf("%d ", arr1[i]); // 通过下标访问,输出:1 2 3 0 0}// 3. 逆序遍历printf("\narr2逆序:");for (int i = sizeof(arr2)/sizeof(arr2[0]) - 1; i >= 0; i--) {printf("%d ", arr2[i]); // 输出:30 20 10}/*=====================二维数组与嵌套遍历======================*/int matrix[2][3] = {{1, 2, 3},{4, 5, 6}};printf("\n二维数组遍历:\n");for (int row = 0; row < 2; row++) {for (int col = 0; col < 3; col++) {printf("matrix[%d][%d]=%d ", row, col, matrix[row][col]);}printf("\n");}/*=====================字符数组与字符串======================*/char str1[] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 手动添加结束符char str2[] = "World"; // 自动添加结束符'\0',长度=5+1=6printf("字符串遍历:");int i = 0;while (str1[i] != '\0') { // 遍历到结束符停止printf("%c", str1[i++]); // 输出:Hello}printf(" %s\n", str2); // 直接输出:World------%s 解释:输出或输入字符串(字符数组)。/*=====================指针数组与遍历======================*/const char *words[] = {"Apple", "Banana", "Cherry"}; // 字符串指针数组printf("指针数组元素:\n");for (int i = 0; i < 3; i++) {printf("第%d个单词: %s\n", i, words[i]); // 通过指针访问字符串}/*=====================动态数组(堆内存)======================*/int *dynamic_arr = malloc(5 * sizeof(int)); // 动态分配5个int空间,开辟长度为5,类型为int的内存空间,if (dynamic_arr == NULL) {printf("内存分配失败!");return 1;}// 初始化动态数组for (int i = 0; i < 5; i++) {dynamic_arr[i] = i * 10; // 下标访问与普通数组一致}// 指针遍历动态数组printf("动态数组:");int *ptr = dynamic_arr;for (int i = 0; i < 5; i++) {printf("%d ", *ptr++); // 输出:0 10 20 30 40}free(dynamic_arr); // 必须释放内存!/*=====================数组下标越界示例(危险!)======================*/int arr[3] = {100, 200, 300};// printf("\n越界访问:%d", arr[5]); // 未定义行为,可能导致崩溃或输出垃圾值return 0;
}
输出:
九. 操作符
操作符 名称/作用 示例 +
加法 a + b
-
减法/负号 a - b
,-x
*
乘法/指针解引用 a * b
,*ptr
/
除法 a / b
%
取模(余数) a % b
++
自增 i++
,++i
--
自减 i--
,--i
>
大于 a > b
<
小于 a < b
==
等于 a == b
!=
不等于 a != b
&&
逻辑与 x && y
!
逻辑非 !x
&
按位与/取地址 m & n
,&var
^
按位异或 m ^ n
~
按位非 ~m
<<
左移 m << 2
>>
右移 n >> 1
=
赋值 c = 10
+=
复合赋值 c += 5
?:
条件运算符 (a>b)?a:b
,
逗号运算符 d=(a++,b++)
.
结构体成员访问 p.x
->
结构体指针成员访问 ptr->x
sizeof
获取类型/对象大小 sizeof(int)
#include <stdio.h>int main() {/*================ 算术操作符 ================*/int a = 10, b = 3;printf("a + b = %d\n", a + b); // 加法:13printf("a - b = %d\n", a - b); // 减法:7printf("a * b = %d\n", a * b); // 乘法:30printf("a / b = %d\n", a / b); // 整除:3(截断小数)printf("a %% b = %d\n", a % b); // 取模:1(余数)/*================ 关系操作符 ================*/printf("a > b? %d\n", a > b); // 大于:1(true)printf("a == b? %d\n", a == b); // 等于:0(false)/*================ 逻辑操作符 ================*/int x = 1, y = 0;printf("x && y = %d\n", x && y); // 逻辑与:0printf("x || y = %d\n", x || y); // 逻辑或:1printf("!x = %d\n", !x); // 逻辑非:0/*================ 位操作符 ================*/unsigned char m = 0b1010, n = 0b1100;printf("m & n = %d\n", m & n); // 按位与:0b1000 (8)printf("m | n = %d\n", m | n); // 按位或:0b1110 (14)printf("m ^ n = %d\n", m ^ n); // 按位异或:0b0110 (6)printf("~m = %d\n", (unsigned char)~m); // 按位非:0b0101 (5)printf("m << 2 = %d\n", m << 2); // 左移:40 (0b101000)printf("n >> 1 = %d\n", n >> 1); // 右移:6 (0b0110)/*================ 赋值操作符 ================*/int c = 10;c += 5; // 等价 c = c + 5 → 15c %= 4; // 等价 c = c % 4 → 3printf("赋值操作后 c = %d\n", c);/*================ 其他操作符 ================*/// 条件运算符(三元运算符)int max = (a > b) ? a : b; // max = 10printf("较大值:%d\n", max);// 逗号运算符(返回最后一个表达式值)int d = (a++, b++, a + b); // a=11, b=4 → d=15printf("逗号运算结果:%d\n", d);// 地址操作符int *ptr = &a; // &取地址printf("a的地址:%p\n", ptr);printf("指针解引用:%d\n", *ptr); // *解引用// sizeof运算符printf("int字节数:%zu\n", sizeof(int)); // 通常为4// 结构体成员访问struct Point { int x; int y; } p = {5, 8};printf("结构体成员:%d\n", p.x); // .运算符访问成员return 0;
}
十. 常见关键字
关键字 类别 核心作用 int/char
基础类型 定义整数/字符类型 float/double
浮点类型 定义单/双精度浮点数 _Bool
布尔类型 定义true/false逻辑值 unsigned
类型修饰符 声明无符号类型 const
类型修饰符 定义不可修改的常量 struct
复合类型 定义结构体数据类型 union
复合类型 定义共享内存的联合体 enum
复合类型 定义枚举常量集合 auto
存储类别 自动存储期(默认) static
存储类别 静态存储期/限制作用域 register
存储类别 建议寄存器存储变量 extern
存储类别 声明外部变量/函数 if/else
流程控制 条件分支控制 for/while
流程控制 循环结构控制 do
流程控制 后置条件循环 switch
流程控制 多条件分支结构 break
流程控制 跳出循环/switch continue
流程控制 跳过本次循环剩余代码 goto
流程控制 无条件跳转(慎用) sizeof
运算符 获取类型/对象内存大小 volatile
类型修饰符 防止编译器优化访问 typedef
类型定义 创建类型别名 void
特殊类型 无类型/函数无返回值 return
函数控制 从函数返回值
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> // 包含_Bool的bool宏/*---------------- 数据类型关键字 ----------------*/
int main() {// 基本类型int num = 10; // int: 32位整型char ch = 'A'; // char: 8位字符/小整型float pi = 3.14f; // float: 单精度浮点double salary = 9999.99;// double: 双精度浮点_Bool flag = true; // _Bool: 布尔类型(需要包含stdbool.h)// 类型修饰符unsigned int age = 30; // unsigned: 无符号整型long big_num = 100000L; // long: 扩展范围整型short small_num = 100; // short: 缩小范围整型const int MAX = 100; // const: 定义不可修改常量// 复合类型struct Person { // struct: 定义结构体类型char name[20];int age;};union Data { // union: 联合体(共享内存)int i;float f;};enum Color {RED, GREEN, BLUE}; // enum: 定义枚举常量/*---------------- 存储类别关键字 ----------------*/auto int local = 5; // auto: 自动存储期(默认可省略)static int counter = 0; // static: 静态存储期register int fast = 0; // register: 建议寄存器存储extern int external; // extern: 声明外部变量/*---------------- 流程控制关键字 ----------------*/// 条件分支if (num > 5) { // if: 条件判断printf("num>5\n");} else { // else: 否则分支printf("num<=5\n");}// 循环结构for (int i=0; i<3; i++) {// for: 确定次数循环printf("for:%d\n",i);continue; // continue: 跳过本次循环}while (num > 0) { // while: 条件循环if (num == 5) break;// break: 跳出循环num--;}do { // do: 后置条件循环printf("do-while\n");} while(0);// 多路分支switch(ch) { // switch: 多条件分支case 'A': // case: 分支匹配printf("A级\n");break;default: // default: 默认分支printf("未知等级\n");}/*---------------- 运算符相关关键字 ----------------*/int size = sizeof(int); // sizeof: 获取类型/对象字节数volatile int sensor; // volatile: 防止编译器优化typedef int Score; // typedef: 定义类型别名/*---------------- 特殊用途关键字 ----------------*/goto cleanup; // goto: 跳转到标签(慎用)cleanup:void *ptr = NULL; // void: 无类型指针/函数无返回值return 0; // return: 函数返回// restrict int *p; // restrict(C99): 指针独占访问优化// _Atomic int atom; // _Atomic(C11): 原子类型
}/*---------------- 补充说明 ----------------*/
// signed int num; // signed: 有符号数(默认可省略)
// unsigned char byte; // 显式声明无符号字符
// inline void func() {} // inline(C99): 内联函数优化
十一. define 定义常量和宏
关键注释说明
宏类型 示例 作用 注意事项 简单常量 #define PI 3.1415
定义全局常量 全大写命名,无分号结尾 函数式宏 #define SQUARE(x) ((x)*(x))
类似函数但无类型检查 参数必须用括号包裹,避免副作用 多语句宏 do { ... } while(0)
安全封装多行代码 使用反斜杠 \
换行字符串化 ( #
)#define STRINGIFY(x) #x
将标识符转为字符串 用于调试输出 连接符 ( ##
)#define CONCAT(a,b) a##b
拼接标识符生成新变量/函数名 避免过度使用降低可读性 可变参数宏 #define LOG(fmt, ...)
支持不定参数 C99+标准支持 条件编译宏 #if DEBUG_MODE ...
根据条件启用/禁用代码块 用于跨平台或调试代码
宏 vs 常量变量
特性 宏 ( #define
)常量变量 ( const
)类型检查 无 有 内存占用 不占用内存 占用内存 调试支持 展开后不可见 可追踪 作用域 文件作用域(除非 #undef
)遵循变量作用域规则 适用场景 简单替换、条件编译 需要类型安全或复杂计算的常量
代码示例:
#include <stdio.h>/*================== 定义常量 ==================*/
// 1. 基础常量(全大写命名规范)
#define PI 3.1415926 // 定义浮点常量
#define MAX_SIZE 100 // 定义整型常量
#define WELCOME_MSG "Hello" // 定义字符串常量/*================== 带参数的宏(函数式宏) ==================*/
// 2. 简单运算宏(参数用括号包裹防止优先级问题)
#define SQUARE(x) ((x) * (x)) // 计算平方
#define MAX(a, b) ((a) > (b) ? (a) : (b)) // 返回较大值// 3. 多语句宏(用 do-while(0) 包裹保证语法安全)
#define PRINT_SUM(a, b) do { \printf("%d + %d = %d\n", a, b, (a)+(b)); \
} while(0)//do-while 循环执行一次后立即退出(0 是假条件)/*================== 高级宏技巧 ==================*/
// 4. 字符串化操作符 (#)
#define STRINGIFY(x) #x // 将参数转为字符串
#define PRINT_VAR(x) printf(#x " = %d\n", x)// 5. 连接操作符 (##)
#define CONCAT(a, b) a##b // 拼接标识符
#define MAKE_VAR(name, num) name##num// 6. 可变参数宏(C99+)
#define LOG(fmt, ...) printf("[LOG] " fmt, __VA_ARGS__)// 7. 条件编译相关宏
#define DEBUG_MODE 1 // 调试模式开关
#if DEBUG_MODE#define DEBUG_LOG(msg) printf("[DEBUG] %s\n", msg)
#else#define DEBUG_LOG(msg)
#endifint main() {// 使用基础常量printf("PI = %.2f\n", PI);printf("MAX_SIZE = %d\n", MAX_SIZE);printf("消息: %s\n", WELCOME_MSG);// 2.使用函数式宏int num = 5;printf("%d的平方 = %d\n", num, SQUARE(num));printf("较大值: %d\n", MAX(10, 20));PRINT_SUM(3, 4); // 输出:3 + 4 = 7// 高级宏演示int value = 100;PRINT_VAR(value); // 输出:value = 100printf("PI的字符串: %s\n", STRINGIFY(PI)); // 输出:PI的字符串: PIint CONCAT(var, 1) = 10; // 生成变量 var1int MAKE_VAR(temp_, 2) = 20; // 生成变量 temp_2printf("var1 = %d, temp_2 = %d\n", var1, temp_2);LOG("结果: %d, 消息: %s\n", 200, "成功"); // [LOG] 结果: 200, 消息: 成功DEBUG_LOG("调试信息"); // 根据DEBUG_MODE开关输出return 0;
}
输出:
十二. 指针(泛谈)
1. 什么是指针?
指针是一种存储变量内存地址的特殊变量。通过指针可以直接访问或操作内存中的数据,是C语言实现高效内存管理和灵活数据操作的核心机制。
2. 指针操作解析表
操作类型 代码示例 核心作用 注意事项 声明与初始化 int *p = &var;
获取变量地址 类型必须匹配 解引用 *p
通过地址访问数据 确保指针已初始化 指针算术 p + i
数组遍历/偏移访问 注意越界问题 动态内存管理 malloc
/free
堆内存分配与释放 必须成对使用,避免内存泄漏 多级指针 int **pp = &p;
操作指针的指针 解引用层级需对应 函数指针 int (*fp)(int, int)
动态调用函数 参数和返回值类型必须匹配 const修饰指针 const int *p
限制数据或指针的修改权限 根据const位置理解限制范围 数组指针 int (*ptr)[3]
操作多维数组 列数必须匹配
3. 代码示例
#include <stdio.h>
#include <stdlib.h>// 函数指针示例
int add(int a, int b) { return a + b; }int main() {/*================= 1. 基础指针操作 =================*/int num = 10;int *p1 = # // 声明指针并初始化为num的地址printf("1. num值: %d, 地址: %p\n", *p1, p1); // *解引用获取值/*================= 2. 指针算术运算 =================*/int arr[] = {10, 20, 30};int *p2 = arr; // 数组名即首元素地址printf("2. 数组遍历:");for (int i = 0; i < 3; i++) {printf(" %d", *(p2 + i)); // 指针加法等价于 arr[i]}printf("\n");/*================= 3. 动态内存管理 =================*/int *heap_ptr = malloc(5 * sizeof(int)); // 堆内存分配if (heap_ptr != NULL) {heap_ptr[0] = 100; // 通过指针操作动态数组free(heap_ptr); // 必须手动释放内存heap_ptr = NULL; // 置空防止野指针}/*================= 4. 多级指针 =================*/int **pp = &p1; // 二级指针:指向指针的指针printf("4. 多级指针值: %d\n", **pp); /*================= 5. 函数指针 =================*/int (*func_ptr)(int, int) = add; // 声明函数指针printf("5. 函数指针运算: %d\n", func_ptr(3, 5));/*================= 6. const与指针 =================*/const int *p3 = # // 指向常量的指针(值不可改)int *const p4 = # // 常量指针(地址不可改)*p4 = 20; // 允许修改值// p4 = NULL; // 错误!地址不可变/*================= 7. 指针与数组的关系 =================*/int matrix[2][3] = {{1,2,3}, {4,5,6}};int (*matrix_ptr)[3] = matrix; // 数组指针:指向二维数组的行printf("7. 二维数组第二行: %d\n", matrix_ptr[1][2]); // 输出6/*================= 8. 空指针与野指针 =================*/int *null_ptr = NULL; // 空指针(安全状态)int *wild_ptr; // 未初始化的野指针(危险!)// printf("%d", *wild_ptr); // 未定义行为(可能崩溃)return 0;
}
输出:
4. 总结
指针的核心概念总结
本质:指针是内存地址的容器,通过地址直接操作数据。
类型安全:指针类型决定了解引用时的内存解释方式(如
int*
与float*
差异)。内存管理:
栈内存:函数局部变量,自动分配释放。
堆内存:手动
malloc
/free
,灵活但需谨慎管理。常见风险:
野指针:未初始化或已释放的指针。
内存泄漏:忘记释放堆内存。
越界访问:指针算术超出合法范围。
5. 最佳实践建议
初始化原则:声明指针时立即赋值(有效地址或
NULL
)。空指针检查:使用动态内存前验证
malloc
返回值。const修饰:根据需求选择
const int*
(保护数据)或int* const
(保护指针)。工具辅助:使用静态分析工具(如Clang静态分析器)检测指针问题。
十三. 结构体(泛谈)
1. 什么是结构体?
结构体(
struct
)是C语言中用于组合多个不同类型变量的自定义复合数据类型,可将逻辑相关的数据封装为单一实体,增强代码可读性和可维护性。
2. 结构体操作解析表
操作类型 代码示例 核心作用 注意事项 结构体定义 struct Student { ... };
创建自定义复合类型 成员可以是任意类型(包括其他结构体) 变量初始化 struct Student stu = {...}
声明并初始化结构体变量 字符串需用 strcpy
赋值成员访问 stu.age
通过 .
访问成员值确保结构体变量已初始化 指针访问 stu_ptr->name
通过指针间接访问成员 指针必须指向有效内存地址 结构体数组 struct Student class[3]
存储多个结构体实例 数组索引从0开始 结构体赋值 stu3 = stu1
浅拷贝所有成员值 含指针成员时需深拷贝 动态内存分配 malloc(sizeof(...))
堆内存中创建结构体 必须手动 free
释放内存嵌套结构体 Line line
构建复杂数据结构 逐级访问成员(如 line.start.x
)函数参数传递 void func(struct Student)
按值或按地址传递结构体 大结构体建议传指针减少拷贝开销
3. 代码示例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>/*================= 1. 结构体定义与初始化 =================*/
// 定义结构体类型
struct Student {char name[50];int age;float score;
};// 使用typedef简化结构体类型名
typedef struct {int x;int y;
} Point;int main() {/*============= 2. 结构体变量声明与初始化 =============*/// 声明并直接初始化struct Student stu1 = {"张三", 20, 85.5};// 先声明后赋值struct Student stu2;strcpy(stu2.name, "李四"); // 字符串需使用strcpystu2.age = 22;stu2.score = 90.0;/*============= 3. 访问结构体成员 =============*/printf("学生1: %s, %d岁, 分数: %.1f\n", stu1.name, stu1.age, stu1.score); // 输出:张三,20岁,85.5/*============= 4. 结构体指针与箭头运算符 =============*/struct Student *stu_ptr = &stu1;printf("指针访问: %s\n", stu_ptr->name); // ->运算符访问成员/*============= 5. 结构体数组 =============*/struct Student class[3] = {{"王五", 19, 88.0},{"赵六", 21, 92.5},{0} // 剩余元素自动初始化为0};printf("数组遍历: %s的分数为%.1f\n", class[1].name, class[1].score); // 赵六:92.5/*============= 6. 结构体赋值与拷贝 =============*/struct Student stu3;stu3 = stu1; // 结构体直接赋值(浅拷贝)stu3.age = 23;printf("拷贝后年龄: %d vs %d\n", stu1.age, stu3.age); // 20 vs 23/*============= 7. 动态内存分配 =============*/struct Student *heap_stu = malloc(sizeof(struct Student));strcpy(heap_stu->name, "孙七");heap_stu->age = 24;heap_stu->score = 95.0;free(heap_stu); // 必须释放内存heap_stu = NULL;/*============= 8. 嵌套结构体 =============*/typedef struct {Point start;Point end;} Line;Line line = {{0, 0}, {10, 10}};printf("线段长度: %.2f\n", sqrt(pow(line.end.x - line.start.x, 2) + pow(line.end.y - line.start.y, 2))); // 14.14/*============= 9. 结构体作为函数参数 =============*/void print_student(struct Student s) {printf("函数参数传递: %s\n", s.name);}print_student(stu1); // 输出:张三return 0;
}
输出:
4. 总结
内存对齐:结构体大小可能大于成员总和(因内存对齐优化),可用
sizeof(struct Student)
查看。深浅拷贝:直接赋值复制所有成员值(浅拷贝),若含指针需手动复制指向数据(深拷贝)。
灵活应用:
构建链表、树等数据结构
封装文件头信息(如BMP文件头)
定义网络协议数据包格式
与联合体区别:结构体成员独立占用内存,联合体成员共享内存。
5. 最佳实践建议
命名规范:结构体类型名首字母大写(如
Student
)。typedef简化:使用
typedef
避免重复写struct
关键字。传参优化:传递大结构体时使用指针(
void func(struct Student *s)
)。内存管理:动态分配的结构体指针使用后立即置空,防止野指针。
相关文章:
C语言快速入门-C语言基础知识
这个c语言入门,目标人群是有代码基础的,例如你之前学过javaSE,看此文章可能是更有帮助,会让你快速掌握他们之间的差异,文章内容大部分都是泛谈,详细的部分我会在之后时间发布,我也在慢慢学习&am…...
Ubuntu 22.04 上安装 VS Code
在 Ubuntu 22.04 上安装 VS Code 的方法如下: 方法 1:通过 APT 包管理器安装 更新系统包索引: 打开终端并执行以下命令: sudo apt update安装依赖项: 执行以下命令以安装所需的依赖项: sudo apt install s…...
AI人工智能-PyCharm的介绍安装应用
下载与安装 创建python项目 项目路径:C:\Users\miloq\Desktop\python_project 配置环境 提前找到conda配置的python-base路径 配置conda环境 运行项目 运行结果...
Todesk介绍
文章目录 ToDesk 软件介绍1. 软件概述2. ToDesk 的功能特点2.1 简单易用2.2 高质量的图像与流畅的操作2.3 跨平台支持2.4 多屏显示与协作2.5 文件传输功能2.6 实时聊天与语音通话2.7 远程唤醒与自动启动2.8 多种权限设置与安全性2.9 无需公网 IP 3. ToDesk 的应用场景3.1 个人使…...
【JavaEE】springMVC返回Http响应
目录 一、返回页面二、Controller和ResponseBody与RestController区别三、返回HTML代码⽚段四、返回JSON五、HttpServletResponse设置状态码六、设置Header6.1 HttpServletResponse设置6.2 RequestMapping设置 一、返回页面 步骤如下: 我们先要在static目录下创建…...
青少年编程与数学 02-011 MySQL数据库应用 02课题、MySQL数据库安装
青少年编程与数学 02-011 MySQL数据库应用 02课题、MySQL数据库安装 一、安装Windows系统Linux系统(以Ubuntu 20.04为例)macOS系统 二、配置(一)Windows系统1. 创建配置文件2. 初始化数据库3. 启动MySQL服务4. 登录MySQL5. 修改ro…...
springboot441-基于SpringBoot的校园自助交易系统(源码+数据库+纯前后端分离+部署讲解等)
💕💕作者: 爱笑学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm…...
【安全运营】关于攻击面管理相关概念的梳理(一)
目录 一、ASM 介绍ASM 是“Attack Surface Management”(攻击面管理)的缩写【框架视角,广义概念】1. 介绍2. 兴起的原因3. 工作流程3.1 资产发现3.2 分类和优先级排序3.3 修复3.4 监控 二、EASM 介绍EASM 是 "External Attack Surface M…...
IPv6 网络访问异常 | 时好时坏 / 部分访问正常
注:本文为 “ IPv6 间接性连接异常” 相关文章合辑。 略作重排,未去重。 如有内容异常,请看原文。 IPv6 间接性连接异常?尝试调整路由器的 MTU 设置 Nero978 2024-1-29 17:54 背景 2024 年 1 月 29 日,因寒假返家…...
Unity编辑器功能及拓展(1) —特殊的Editor文件夹
Unity中的Editor文件夹是一个具有特殊用途的目录,主要用于存放与编辑器扩展功能相关的脚本和资源。 一.纠缠不清的UnityEditor 我们Unity中进行游戏构建时,我们经常遇到关于UnityEditor相关命名空间丢失的报错,这时候,只得将报错…...
LLMs之PE:《Tracing the thoughts of a large language model》翻译与解读
LLMs之PE:《Tracing the thoughts of a large language model》翻译与解读 导读:这篇论文的核心贡献在于提出了一种新颖的、基于提示工程的LLMs推理过程追踪技术——“Tracing Thoughts”。该技术通过精心设计的提示,引导LLMs生成其推理过程的…...
[Python] 贪心算法简单版
贪心算法-简单版 贪心算法的一般使用场景是给定一个列表ls, 让你在使用最少的数据的情况下达到或超过n. 我们就来使用上面讲到的这个朴素的例题来讲讲贪心算法的基本模板: 2-1.排序 既然要用最少的数据, 我们就要优先用大的数据拼, 为了实现这个效果, 我们得先给列表从大到小…...
游戏引擎学习第191天
回顾并制定今天的计划 最近几天,我们有一些偏离了原计划的方向,主要是开始了一些调试代码的工作。最初我们计划进行一些调试功能的添加,但是随着工作的深入,我们开始清理和整理调试界面的呈现方式,以便能够做一些更复…...
Git撤回操作全场景指南:未推送与已推送,保留和不保留修改的差异处理
一、未推送到远程仓库的提交(仅本地存在) 特点:可直接修改本地提交历史,不会影响他人 1. 保留修改重新提交 git reset --soft HEAD~1 # 操作效果: # - 撤销最后一次提交 # - 保留工作区所有修改 # - 暂存区内容保持…...
Java 贪吃蛇游戏
这段 Java 代码实现了一个经典的贪吃蛇游戏。玩家可以使用键盘的上下左右箭头键控制蛇的移动方向,蛇会在游戏面板中移动并尝试吃掉随机生成的食物。每吃掉一个食物,蛇的身体会变长,玩家的得分也会增加。如果蛇撞到自己的身体或者撞到游戏面板…...
QT图片轮播器(QT实操学习2)
1.项目架构 1.UI界面 2.widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>#define TIMEOUT 1 * 1000 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent n…...
mac m1/m2/m3 pyaudio的安装
google了很多方法,也尝试了 issue68的方法, 但是均失败了,但是问deepseek竟然成功了,下面是deepseek r1给出的方法。在M3 pro芯片上可以成功运行. 安装homebrew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent…...
Appium中元素定位的注意点
应用场景 了解这些注意点可以以后在出错误的时候,更快速的定位问题原因。 示例 使用 find_element_by_xx 或 find_elements_by_xx 的方法,分别传入一个没有的“特征“会是什么结果呢? 核心代码 driver.find_element_by_id("xxx") drive…...
《深入探索 Python 数据分析:用 Pandas 高效处理与可视化大型数据集》
《深入探索 Python 数据分析:用 Pandas 高效处理与可视化大型数据集》 引言:从零到分析高手 数据是当代社会最宝贵的资源,而数据分析技能是现代职业人不可或缺的一部分。在数据科学的领域中,Python 已成为当之无愧的“首选语言”,其强大的生态系统和简洁的语法让人如虎添…...
[GWCTF 2019]我有一个数据库1 [CVE phpMyAdmin漏洞]
扫出来一些东西 访问/phpmyadmin 发现界面 这里用到了CVE-2018-12613,光速学习 出现漏洞的代码是: $target_blacklist array (import.php, export.php );// If we have a valid target, lets load that script instead if (! empty($_REQUEST[targe…...
spring 常用注解区别及使用场景
1. 组件注册注解 Bean 作用:用于方法上,表示该方法返回的对象由Spring容器管理。通常用于配置类(Configuration)中,注册第三方库或自定义的Bean。 使用场合: 当你需要将非Spring管理的类(如第…...
【后端】【Django】信号使用详解
Django post_save 信号使用详解(循序渐进) 一、信号的基本概念 Django 的 信号(Signal) 允许不同部分的代码在发生某些事件时进行通信,而不需要直接调用。这种机制可以解耦代码,让不同的模块独立工作。 …...
ML算法数学概念
交叉熵损失(Cross-Entropy Loss) 是机器学习和深度学习中常用的一种损失函数,主要用于衡量两个概率分布之间的差异。它在分类问题中(尤其是多分类问题)被广泛使用,因为它能够有效地评估模型预测的概率分布与…...
wps 怎么显示隐藏文字
wps 怎么显示隐藏文字 》文件》选项》视图》勾选“隐藏文字” wps怎么设置隐藏文字 wps怎么设置隐藏文字...
Vue3 其它API Teleport 传送门
Vue3 其它API Teleport 传送门 在定义一个模态框时,父组件的filter属性会影响子组件的position属性,导致模态框定位错误使用Teleport解决这个问题把模态框代码传送到body标签下...
亚马逊玩具品类技术驱动型选品策略:从趋势洞察到合规基建
一、全球玩具电商技术演进趋势 (技术化重构原市场背景) 数据可视化分析:通过亚马逊SP-API抓取2023年玩具品类GMV分布热力图 监管技术升级: 美国CPSC启用AI质检系统(缺陷识别准确率92.7%) 欧盟EPR合规接口…...
SpringBoot3+EasyExcel通过WriteHandler动态实现表头重命名
方案简介 为了通过 EasyExcel 实现动态表头重命名,可以封装一个方法,传入动态的新表头名称列表(List<String>),并结合 WriteHandler 接口来重命名表头。同时,通过 EasyExcel 将数据直接写入到输出流…...
PHY——LAN8720A 寄存器读写 (二)
文章目录 PHY——LAN8720A 寄存器读写 (二)工程配置引脚初始化代码以太网初始化代码PHY 接口实现LAN8720 接口实现PHY 接口测试 PHY——LAN8720A 寄存器读写 (二) 工程配置 这里以野火电子的 F429 开发板为例,配置以太网外设 这里有一点需要注意原理图 RMII_TXD0…...
HTML5和CSS3的一些特性
HTML5 和 CSS3 是现代网页设计的基础技术,它们引入了许多新特性和功能,极大地丰富了网页的表现力和交互能力。 HTML5 的一些重要特性包括: 新的语义化标签: HTML5 引入了一些重要的语义化标签如 <header>, <footer>, <articl…...
sass报错,忽略 Sass 弃用警告,降级版本
最有效的方法是创建一个 .sassrc.json 文件来配置 Sass 编译器。告诉 Sass 编译器忽略来自依赖项的警告消息。 解决方案: 1. 在项目根目录创建 .sassrc.json 文件: {"quietDeps": true }这个配置会让 Sass 编译器忽略所有来自依赖项&#x…...
DeepSeek+Kimi:PPT制作的效率革命
摘要:传统PPT制作面临模板选择困难、内容逻辑混乱、设计排版能力有限以及反复修改等问题。DeepSeek和Kimi两款AI工具的组合为PPT制作提供了全新的解决方案。DeepSeek擅长内容生成与逻辑推理,能够快速生成高质量的PPT大纲和内容;Kimi则专注于长…...
transformers中学习率warmup策略具体如何设置
在使用 get_linear_schedule_with_warmup(如 Hugging Face Transformers 库中的学习率调度器)时,参数的合理设置需要结合 数据量(dataset size)、批次大小(batch size) 和 训练轮数(…...
linux实现rsync+sersync实时数据备份
1.概述 rsync(Remote Sync) 是一个Unix/linux系统下的文件同步和传输工具 2.端口和运行模式 tcp/873 采用C/S模式(客户端/服务器模式) 3.特点 可以镜像保存整个目录和文件第一次全量备份(备份全部的文件),之后是增量备份(只备份变化的文件) 4. 数…...
CTF类题目复现总结-[MRCTF2020]ezmisc 1
一、题目地址 https://buuoj.cn/challenges#[MRCTF2020]ezmisc二、复现步骤 1、下载附件,得到一张图片; 2、利用010 Editor打开图片,提示CRC值校验错误,flag.png应该是宽和高被修改了,导致flag被隐藏掉;…...
『Linux』 第十一章 线程同步与互斥
1. 线程互斥 1.1 进程线程间的互斥相关背景概念 临界资源:多线程执行流共享的资源就叫做临界资源临界区:每个线程内部,访问临界资源的代码,就叫做临界区互斥:任何时刻,互斥保证有且只有一个执行流进入临界…...
【数据结构】队列
目录 一、队列1、概念与结构2、队列的实现3、队列的初始化4、打印队列数据5、入队6、销毁队列7、队列判空8、出队9、取队头、队尾数据10、队列中有效元素个数 二、源码 个人主页,点击这里~ 数据结构专栏,点击这里~ 一、队列 1、概念与结构 概念&#x…...
【导航定位】GNSS数据协议-RINEX OBS
RINEX协议 RINEX(Receiver INdependent EXchange format,与接收机无关的交换格式)是一种在GPS测量应用中普遍采用的标准数据格式,该格式采用文本文件形式(ASCII码)存储数据数据记录格式与接收机的制造厂商和具体型号无关。目前RINEX版本已经发布到了4.x…...
Qt中的事件循环
Qt的事件循环是其核心机制之一,它是一种消息处理机制,负责处理各种事件(如用户输入、定时器、网络请求等)的分发和处理。Qt中的事件循环是一个持续运行的循环,负责接收事件并将它们分发给相应的对象进行处理。当没有事件需要处理时࿰…...
Android并发编程:线程池与协程的核心区别与最佳实践指南
1. 基本概念对比 特性 线程池 (ThreadPool) 协程 (Coroutine) 本质 Java线程管理机制 Kotlin轻量级并发框架 最小执行单元 线程(Thread) 协程(Coroutine) 创建开销 较高(需分配系统线程资源) 极低(用户态调度) 并发模型 基于线程的抢占式调度 基于协程的协作式调度 2. 核心差异…...
吴恩达深度学习复盘(2)神经网络的基本原理轮廓
笔者注 这两节课主要介绍了神经网络的大的轮廓。而神经网络基本上是在模拟人类大脑的工作模式,有些仿生学的意味。为了便于理解,搜集了一些脑神经的资料,这部分是课程中没有讲到的。 首先要了解一下大脑神经元之间结构。 细胞体࿱…...
【redis】集群 数据分片算法:哈希求余、一致性哈希、哈希槽分区算法
文章目录 什么是集群数据分片算法哈希求余分片搬运 一致性哈希扩容 哈希槽分区算法扩容相关问题 什么是集群 广义的集群,只要你是多个机器,构成了分布式系统,都可以称为是一个“集群” 前面的“主从结构”和“哨兵模式”可以称为是“广义的…...
计算机组成原理笔记(六)——2.2机器数的定点表示和浮点表示
计算机在进行算术运算时,需要指出小数点的位置,根据小数点的位置是否固定,在计算机中有两种数据格式:定点表示和浮点表示。 2.2.1定点表示法 一、基本概念 定点表示法是一种小数点的位置固定不变的数据表示方式,用于表示整数或…...
将树莓派5当做Ollama服务器,C#调用generate的API的示例
其实完全没这个必要,性能用脚后跟想都会很差。但基于上一篇文章的成果,来都来了就先简单试试吧。 先来看看这个拼夕夕上五百多块钱能达到的效果: 只要对速度没要求,那感觉就还行。 Ollama默认只在本地回环(127.0.0…...
MYSQL数据库(一)
一.数据库的操作 1.显示数据库 show databases; 2.创建数据库 create database 数据库名; 3.使用数据库 use 数据库名; 4.删除数据库 drop database 数据库名; drop database if exists 数据库名; 二.表的操作 1.显示所有表 show tables; 2.查看表结构 des…...
Python Cookbook-4.15 字典的一键多值
任务 需要一个字典,能够将每个键映射到多个值上。 解决方案 正常情况下,字典是一对一映射的,但要实现一对多映射也不难,换句话说,即一个键对应多个值。你有两个可选方案,但具体要看你怎么看待键的多个对…...
IDEA 终端 vs CMD:为什么 java -version 显示的 JDK 版本不一致?
前言:离谱的 JDK 版本问题 今天遇到了一个让人抓狂的现象:在 Windows 的 CMD 里输入 java -version 和在 IntelliJ IDEA 终端输入 java -version,居然显示了不同的 JDK 版本! 本以为是环境变量、缓存或者 IDEA 设置的问题&#x…...
Flask登录页面后点击按钮在远程CentOS上自动执行一条命令
templates文件夹和app.py在同一目录下。 templates文件夹下包括2个文件:index.html login.html app.py代码如下: import os import time from flask import Flask, render_template, request, redirect, session, make_response import mysql.con…...
深度解析:文件夹变白色文件的数据恢复之道
在数字化时代,数据的重要性不言而喻。然而,当我们在使用计算机时,偶尔会遇到一些棘手的问题,其中“文件夹变白色文件”便是一个令人困惑且亟待解决的难题。这一现象不仅影响了文件的正常访问,更可能隐藏着数据丢失的风…...
【Matlab】-- 基于MATLAB的飞蛾扑火算法与反向传播算法的混凝土强度预测
文章目录 文章目录 01 内容概要02 MFO-BP模型03 部分代码04 运行结果05 参考文献06 代码下载 01 内容概要 本资料介绍了一种基于飞蛾扑火算法(Moth Flame Optimization, MFO)与反向传播算法(Backpropagation, BP)的混凝土强度预…...
【Python实例学习笔记】图像相似度计算--哈希算法
【Python实例学习笔记】图像相似度计算--哈希算法 一、哈希算法的实现步骤:二、对每一步都进行注解的代码 一、哈希算法的实现步骤: 1、缩小尺寸: 将图像缩小到8*8的尺寸,总共64个像素。这一步的作用是去除图像的细节,…...