一站式学习C编程
上篇 C语言入门
第1章 程序的基本概念
1.1 程序和编程语言
-
- 解释执行的语言和编译执行的语言是两种不同的语言执行方式,它们各自有一些优点和缺点。
解释执行的语言:
优点:
跨平台性: 解释器通常是与平台无关的,因此相同的源代码可以在不同的平台上运行,而不需要重新编译。
灵活性: 修改源代码后可以立即运行,无需等待编译过程。
调试方便: 在运行时检查错误,可以逐行调试,更容易发现和修复问题。
学习和使用简单: 对于初学者来说,通常更容易学习和理解。
缺点:
性能相对较低: 解释执行通常比编译执行慢,因为代码在运行时被逐行解释。
依赖解释器: 在目标机器上必须存在相应的解释器,限制了程序的独立性。
源代码需要保护: 因为源代码是直接可见的,所以可能存在安全性和知识产权的问题。
编译执行的语言:
优点:
性能较高: 编译过程将源代码转换为机器代码,执行速度更快。
独立性: 编译后的程序通常不依赖于源代码或编译器,可以在不同的计算机上运行。
代码隐藏: 由于编译后的代码不是直接可读的源代码,可以更好地保护知识产权和程序的安全性。
缺点:
平台依赖性: 编译生成的代码通常与特定平台相关,需要重新编译才能在不同的平台上运行。
编译时间较长: 编译执行需要花费时间将源代码转换为机器代码,这可能会导致开发周期的延长。
调试相对困难: 调试通常需要在源代码级别进行,而不是在生成的机器代码上进行,这可能使调试变得更加复杂。
选择解释执行还是编译执行通常取决于具体的应用场景和需求。有些语言甚至采用了混合模式,结合了两种执行方式的优点。
1.4 第一个程序
- main.c
#include <stdio.h>
/* main: generate some simple output */
int main(void)
{
printf(0);
return 0;
}
gcc -Wall main.c
1. warning: argument 1 null where non-null expected [-Wnonnull]
这是一个编译器或静态代码分析工具发出的警告信息,提示在某个地方使用了一个被声明为不可为空(non-null)的参数,但实际传入的值是空(null)。
具体来说,这种警告的意思是:
argument 1: 表示在函数或方法的调用中,问题出现在第一个参数。
null: 表示实际传入的值是空(null)。
non-null expected: 表示在该位置,该参数是不可为空的,也就是说,该参数不应该接受空值。
[-Wnonnull]: 这部分通常是指警告的标志或编译选项,这里的“-Wnonnull”可能是告诉编译器要检测非空性的警告。
这样的警告通常是为了帮助开发者在编译阶段发现一些潜在的程序错误,特别是在使用编程语言支持空值和非空值的情况下。在实际代码中,你可能需要检查在这个位置上的参数是否应该为非空,并确保传入的值符合预期。解决这个问题的方式可能包括添加空值检查、调整参数类型或确保传入的参数不为空。
2. warning: null format string [-Wformat-overflow=]
这一部分的警告是告诉你在 main.c 文件的 main 函数的第 5 行调用 printf 时,传递了一个空的格式化字符串。这也是一个潜在的错误,因为 printf 函数需要一个格式化字符串来指定如何输出后续参数。
你应该确保在 printf 中传递一个有效的格式化字符串,例如 printf("%d", 0);,这里 %d 表示将整数 0 以十进制形式输出。
第2章 常量、变量和表达式
2.2 常量
- 在C语言中,如果你想在printf的格式化字符串中表示一个%字符,你需要使用两个%来转义表示。这是因为 % 在 printf 中是一个特殊字符,用于指示后面的内容是要被格式化的变量。因此,为了输出一个普通的 % 字符,你需要写成 %%。
以下是一个简单的C程序演示如何在 printf 中表示 % 字符:
#include <stdio.h>
int main() {
// 使用 %% 来表示 %
printf("This is a percent sign: %%\n");
return 0;
}
在这个例子中,printf(“This is a percent sign: %%\n”); 会输出 “This is a percent sign: %"。在格式化字符串中,%% 被解释为一个普通的 % 字符。
2.5 表达式
- 假设变量x和n是两个正整数,我们知道x/n 这个表达式的结果要取Floor,例如x是17,n是4, 则结果是4。如果希望结果取Ceiling应该怎么写表达式呢?例如x是17,n是4,则结果是5;x是16, n是4,则结果是4。
#include <stdio.h>
#include <math.h>
int main() {
int x = 17;
int n = 4;
int result = (x + n - 1) / n;
printf("向上取整的结果为: %d\n", result);
return 0;
}
这个表达式的核心思想是,在除法操作之前,先将被除数 x 加上 n - 1,这样就确保了在进行除法操作时,能够达到向上取整的效果。在这个例子中,结果是 (17 + 4 - 1) / 4,即 20 / 4,结果为 5。
这个方法适用于任何正整数 x 和正整数 n 的情况。
第3章 简单函数
3.1 数学函数
#include <math.h>
#include <stdio.h>
int main(void)
{
double pi = 3.1416;
printf("sin(pi/2)=%f\nln1=%f\n", sin(pi/2), log(1.0));
return 0;
}
gcc -Wall main.c -o main
/usr/bin/ld: /tmp/ccuTgF4O.o: in function `main':
main.c:(.text+0x31): undefined reference to `sin'
collect2: error: ld returned 1 exit status
在链接阶段“对 sin’” error typically occurs when the linker is unable to find the implementation of the sin` 函数的未定义引用。此问题通常与未链接的数学库有关。
gcc your_program.c -o your_program -lm
-lm
在链接阶段添加数学库
使用math.h中声明的库函数还有一点特殊之 处,gcc命令行必须加-lm选项,因为数学函数位于 libm.so库文件中(这些库文件通常位于/lib目录下),-lm选项告诉编译器,我们程序中用到的数学函数要到这个库文件里找。
第4章 分支语句
4.2 if else
- 写一个函数,参数是整型变量x,功能是打印x的个位和十位。
#include <stdio.h>
void printDigits(int x) {
// 获取十位和个位数字
int tenDigit = (x / 10) % 10;
int unitDigit = x % 10;
// 打印十位和个位数字
printf("十位数字:%d,个位数字:%d\n", tenDigit, unitDigit);
}
int main() {
// 示例:调用函数并传递整数值
int number = 42;
printDigits(number);
return 0;
}
第5章 深入理解函数
- 编写一个布尔函数int is_leap_year(int year),判断参数year是不是闰年。如果某年份能被 4整除,但不能被100整除,那么这一年就是闰 年,此外,能被400整除的年份也是闰年。
#include <stdio.h>
// 布尔函数,判断是否为闰年
int is_leap_year(int year) {
// 如果能被400整除,或者能被4整除但不能被100整除,则是闰年
if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))) {
return 1; // 是闰年
} else {
return 0; // 不是闰年
}
}
int main() {
// 示例:调用函数并传递年份值
int year = 2024;
if (is_leap_year(year)) {
printf("%d年是闰年\n", year);
} else {
printf("%d年不是闰年\n", year);
}
return 0;
}
- 编写一个函数double myround(double x),输入一个小数,将它四舍五入。例如 myround(-3.51)的值是-4.0,myround(4.49)的值 是4.0。可以调用math.h中的库函数ceil和floor实 现这个函数,代码要尽可能简洁高效。
#include <math.h>
// 四舍五入函数
double myround(double x) {
return (x >= 0.0) ? floor(x + 0.5) : ceil(x - 0.5);
}
int main() {
// 示例:调用函数并传递小数值
double num1 = -3.51;
double num2 = 4.49;
printf("myround(%g) = %g\n", num1, myround(num1));
printf("myround(%g) = %g\n", num2, myround(num2));
return 0;
}
第6章 循环语句
6.4 break和continue语句
- 画菱形
void diamond(int x, char m)
{
if(x%2 != 0){
int n = x/2 +1;
for(int y=1; y <= n; y++) {
for (int i=1;i<=(n-y);i++) printf(" ");
for (int i=1;i<=(y*2-1);i++) printf("%c",m);
for (int i=1;i<=(n-y);i++) printf(" ");
printf("\n");
}
for(int y=n-1; y >= 1; y--) {
for (int i=1;i<=(n-y);i++) printf(" ");
for (int i=1;i<=(y*2-1);i++) printf("%c",m);
for (int i=1;i<=(n-y);i++) printf(" ");
printf("\n");
}
}
else printf("Error!\n");
}
第7章 结构体
7.2 数据抽象
实现一个用分子分母的格式来表示有理数的 结构体rational以及相关的函数,rational结构体之间可以做加减乘除运算,运算的结果仍然是 rational。测试代码如下: 注意要约分为最简分数,例如1/8和-1/8相减的 打印结果应该是1/4而不是2/8,可以利用第5.3节 习题中的Euclid算法来约分。在动手编程之前先思 考一下这个问题实现了什么样的数据抽象,抽象层 应该由哪些函数组成。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
// 递归函数实现 Euclid 算法求最大公约数
int gcd(int a, int b)
{
if (abs(b) == 0) {
return abs(a); // 当b为0时,a即为最大公约数
} else {
return gcd(b, a % b); // 否则,递归调用gcd函数
}
}
//最小公倍数
int cm(int a, int b)
{
return a*b/gcd(a,b);
}
//定义分数 结构体
struct rational
{
int x, y;
};
struct rational make_rational(int a, int b)
{
struct rational z;
if(b < 0)
{
a = -a;
b = -b;
}
int gv = gcd(a,b);
z.x = a / gv;
z.y = b / gv;
return z;
}
struct rational add_rational(struct rational a, struct rational b)
{
struct rational z;
int cmv = cm(a.y,b.y);
z.y = cmv;
z.x = cmv / a.y * a.x + cmv / b.y * b.x;
z = make_rational(z.x,z.y);
return z;
}
struct rational sub_rational(struct rational a, struct rational b)
{
struct rational z;
int cmv = cm(a.y,b.y);
z.y = cmv;
z.x = cmv / a.y * a.x - cmv / b.y * b.x;
z = make_rational(z.x,z.y);
return z;
}
struct rational mul_rational(struct rational a, struct rational b)
{
struct rational z;
z.y = a.y * b.y;
z.x = a.x * b.x;
z = make_rational(z.x,z.y);
return z;
}
struct rational div_rational(struct rational a, struct rational b)
{
struct rational z;
z.y = a.y * b.x;
z.x = a.x * b.y;
z = make_rational(z.x,z.y);
return z;
}
void print_rational(struct rational c)
{
printf("%d/%d\n",c.x,c.y);
}
int main(void)
{
struct rational a = make_rational(1,8);
struct rational b = make_rational(-1,8);
print_rational(add_rational(a,b));
print_rational(sub_rational(a,b));
print_rational(mul_rational(a,b));
print_rational(div_rational(a,b));
return 0;
}
专业英语
- Delimiter 界定符
- Asterisk *号
- Coding Style 代码风格
- Nest 嵌套
- comment 注释
- Backward Compatibility 向后兼容性
- ANSI(American National Standards Institute) 美国国家标准委员会
- Double Quote 双引号
- Single Quote 单引号
- String Literal 字符串字面值
- Escape Sequence 转义序列
- Line Feed 换行符
- Form Feed 分页符
- Carriage Return 回车
- Backspace 退格
- Backslash 反斜线
- Question Mark 问号
- Vertical Tab 垂直制表符
- Horizontal Tab 水平制表符
- Constant 常量
- Character 字符
- Integer 整数
- Floating Point 浮点数
- Type 类型
- Format String 格式化字符串
- Percent Sign %号
- Conversion Specification 转换说明
- Placeholder 占位符
- Variable 变量
- Value 值
- Declaration 声明
- Definition 定义
- Identifier 标识符
- Keyword 关键字
- Reserved Word 保留字
- Assignment 赋值
- Initialization 初始化
- Operator 运算符
- Operand 操作符
- Expression 表达式
- Precedence 优先级
- Parenthesis 括号
- Associativity 结合性
- Composition 组合
- ASCII(American Standard Code for Information Interchange)
- Character Encoding 字符编码
- Side Effect 副作用
- Generalize 泛化
- Pound Sign, Number Sign, Hash Sign #号
- Header File 头文件
- Angle Bracket 尖括号
- Parameter 形参
- Argument 实参
- Interface 接口
- Branch 分支
- Control Flow 控制流程
- Controlling Expression 控制表达式
- Equality Operator 相等性运算符
- Relational Operator 关系运算符
- Statement Block 语句块
- Modulo 取模
- Remainder 余数
- even 偶数
- odd 奇数
- Parity 奇偶性
- Trancate towards Zero 向0截断
- Ampersand &与号,and符号
- Logical AND 逻辑与
- Logical OR 逻辑或
- Logical NOT 逻辑非
- Pipe Sign |线
- Exclamation Mark !号
- Unary Operator 单目运算符
- Binary Operator 双目运算符
- Boolean Algebra 布尔代数
- Incremental 增量式
- Scaffold 脚手架
- Stack 堆栈
- Stack Frame 栈帧
- Leap of Faith 信仰的飞跃
- Mathematical Induction 数学归纳法
- Iteration 迭代
- Loop 循环
- Accumulator 累加器
- Functional Programming 函数式编程
- Imperative Programming 命令式编程
- Infinite Loop 无限循环
- Primitive Type 基本类型
- Compound Type 复合类型
- Data Abstraction 数据抽象
- Period .号,后缀运算符
- Abstraction Layer 抽象层
文档信息
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
- 发表日期: 2023-11-15T08:52:04+08:00