前言:本篇文章主要涉及笔者学习的以下几个主题:
-
变量的作用域和生命周期:
- 全局变量的作用域是整个工程,可以使用
extern
函数引用。 - 展示了局部变量的生命周期,生命周期结束意味着程序执行结束。
- 全局变量的作用域是整个工程,可以使用
-
常量和变量:
- 使用
const
修饰常变量,展示了常量的属性。 - 通过数组验证
const
修饰的变量本质上还是变量,不允许再被修改。 - 使用
#define
定义标识符常量。 - 枚举常量的创建和使用。
- 使用
-
字符串:
- 展示了字符和字符串的定义方式。
- 介绍了字符串末尾默认以
\0
结尾的特性。 - 使用库函数
strlen()
计算字符串长度。
-
使用转义字符进行进制转换:
- 展示了一些使用转义字符进行进制转换的例子。
-
选择语句和循环语句:
- 展示了简单的if-else结构和while循环结构。
-
函数:
- 展示了函数的定义和调用,以及函数的作用。
- 通过一个求两个整数之和的例子演示了函数的使用。
-
数组:
- 展示了数组的定义和遍历。
-
C语言中的操作符:
- 包括算术操作符、移位操作符、位操作符、赋值操作符等。
-
前置++、后置++、--(新手容易困惑):
- 展示了前置和后置递增/递减操作符的使用。
每个主题都有相应的代码示例,用于说明相关概念和语法。
主题1: 变量的作用域和生命周期:
// 示例代码
int a = 10; // 全局变量的作用域:整个工程,可用extern函数引用
extern int a; // 声明一个符号
int main() {
int a = 20;
printf("%d", a);
return 0;
}
// 生命周期-即作用域内:
int main() {
int a = 10;
printf("这是a的值%d", a);
{
int b = 20;
printf("这是b的值", b);
} // 变量b的生命周期就是在这个括号内(作用域内)
} // 主函数的生命周期结束就意味着程序执行结束。
主题2: 常量和变量:
// 示例代码
const int a = 20;
// a = 10; // 报错:不能赋值给const限定类型const int的变量'a'
int main() {
const int n = 10;
int arr[n] = {0}; // 报错:可变长度数组作为扩展折叠为常量数组
// 说明n仍为变量
return 0;
}
// 使用define定义标识符常量(常量:也是不可修改的)
#define MAX 100
#define STR "abcd"
int main() {
printf("这是使用define定义的标识符常量,值为:%d\n", MAX);
printf("作为字符串输出:%s\n", STR);
int a = MAX;
printf("把MAX传给了a:%d\n", a);
return 0;
}
// 枚举常量enum:(枚举enum:一一列举出来)
enum Color {
RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE
};
int main() {
int num = 7;
enum Color c = RED;
return 0;
}
主题3: 字符串:
// 示例代码
char arr_1[] = "abcdefg"; // 7个字符,(有\0)
char arr_2[] = {'a','b','c','d','e','f','\0'};
printf("%s\n", arr_1);
printf("%s\n", arr_2);
主题4: 使用转义字符进行进制转换:
// 示例代码
#include <stdio.h>
printf("%c\n", '\130'); // 130对应的ASCII码值:X
printf("%d\n", 'a'); // 97
printf("%d\n", 'A'); // 65
printf("%d\n", '\x63'); // 99 :16进制的x63的ASCII码值为99
printf("%c\n", '\x63'); // c 的ASCII码值为99
printf("%c\n", '\x64'); // d
主题5: 选择语句和循环语句:
// 示例代码
// 选择结构:
int main() {
int days = 0;
printf("请输入骨折天数:");
scanf("%d", &days);
if (days >= 90) {
printf("可以脱拐了!");
} else {
printf("加油康复,胜利就在眼前!");
}
return 0;
}
// 循环结构的:
int main() {
int days = 0;
while (days <= 90) {
printf("骨折天数:%d\n", days);
days++;
}
printf("可以脱拐啦!");
return 0;
}
主题6: 函数:
// 示例代码
int Add(int x, int y) {
return (x + y);
}
int main() {
int a = 10, b = 20;
int sum = Add(a, b);
printf("%d\n", sum);
return 0;
}
主题7: 数组:
// 示例代码
int arr[10] = {10, 11, 12, 13, 14, 15, 16, 17};
int i = 0;
while (i < 10) {
printf("数组的第%d个元素为%d\n", i + 1, i);
i = i + 1;
}
主题8: C语言中的操作符:
// 示例代码
int a = 7, b = 3;
printf("%d\n", a / b); // 7/3:商2余1,结果为2
printf("%d\n", a % b); // 7%3:商2余1,结果为1
主题9: 前置++、后置++、--:
// 示例代码
int a = 10;
int b = a++; // 先使用a,后++,即:int b = a,a=a+1
int c = ++a; // 先++,后使用,即:int a=a+1, c = a
printf("%d,%d,%d", a, b, c);
每个主题都包含了相关的示例代码,以便更清晰地展示不同的概念和语法。
源代码及运行结果:
/**变量的作用域和生命周期:**/
//int a = 10; // 全局变量的作用域:整个工程,可用extern函数引用:
//extern int a; // 声明一个符号
//
//int main()
//{
// int a = 20;
// printf("%d",a);
// return 0;
//}
// 生命周期-即作用域内:
//int main()
//{
// int a = 10;
// printf("这是a的值%d",a);
// {
// int b = 20;
// printf("这是b的值",b);
// } // 变量b的生命周期就是在这个括号内(作用域内)
//} // 主函数的生命周期结束就意味着程序执行结束。
/**常量和变量:**/
// const 修饰常变量:“变量不允许被修改”:有着常量的属性:即“常变量”:
// “const修饰常变量”,ps:但其本质上还是变量,下面将使用数组验证;
//int main()
//{
// const int a = 20;
//// a = 10; // 报错:不能赋值给const限定类型const int的变量'a'
// printf("%d",a);
//
// return 0;
//}
//ps:const修饰的变量本质上还是变量,仅仅是不允许再被修改了,
// 下面将使用数组验证:(利用数组的参数必须是常量的特性):
// 创建一个变量n,再使用const修饰它,然后将其传入数组arr[],
// 若可用,则说明n此时为常量,反之为变量:
//int main()
//{
// const int n = 10;
// int arr[n] = {0}; // 报错:可变长度数组作为扩展折叠为常量数组
// // 说明n仍为变量
// return 0;
//}
/**使用define定义标识符常量(常量:也是不可修改的):**/
//#define MAX 100
//#define STR "abcd"
//
//int main()
//{
// printf("这是使用define定义的标识符常量,值为:%d\n",MAX);
// printf("作为字符串输出:%s\n",STR);
// // 也可以将定义的符号常量赋值给其它变量使用:
// int a = MAX;
// printf("把MAX传给了a:%d\n",a);
// return 0;
//}
////这是使用define定义的标识符常量,值为:100
////作为字符串输出:abcd
////把MAX传给了a:100
/**枚举常量enum:(枚举enum:一一列举出来)**/
// 使用关键字enum创建枚举常量:七色彩虹
//enum Color // 枚举常量color:常量名一般大写
// {
// RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE // 枚举常量的可能取值
// };
//int main()
//{
// int num = 7; // 类似于这样创建变量,枚举常量也可以创建:
// enum Color c = RED; // 创建枚举常量c,并赋值为RED
//// ps:枚举类型也是可以输出的,值默认从0开始
//
// return 0;
//}
/**字符串:**/
// 字符类型:char: a
// 字符串:”用双引号括起来的字符类型“: char ch = "a"
//int main()
//{
//// char arr_1[10] = "qwer"; // 创建一个字符串数组,大小为10
//// char arr_2[] = "qwer"; // 创建一个字符串数组,参数不写,则大小自动分配
//// ps:字符串末尾默认以“\0”结尾,不显示,(\0 是字符串的结束标志)
//// 下面分别传参测试:
// char arr_1[] = "abcdefg"; // 7个字符,(有\0)
//// char arr_2[] = {'a','b','c','d','e','f'};
// // 6个字符,(无\0)
//// 手动添加\0:
// char arr_2[] = {'a','b','c','d','e','f','\0'};
//
// printf("%s\n",arr_1);
// printf("%s\n",arr_2);
//
// return 0;
//}
// 看一下输出结果:
// abcdef
// abcdefabcdef
/**为什么会这样呢?**/
// 因为字符串默认以\0结束,arr1的f后面有\0,所以到f就结束了,不再往内存空间中寻找下一个字符;
// 而arr2中是单个字符,没有\0,而遇到\0时才会认为字符串结束,所以只能继续在内存空间中往下寻找,
// 直到遇见\0,由此,结合打印结果可知,arr_1在内存空间中位于arr2的后面:
// 在arr1后面加一个g,再打印一下:
//abcdefg
//abcdefabcdefg 是的,结合打印结果可知,arr_1在内存空间中位于arr2的后面。
// 也可以手动加一个\0:正常结束:
//abcdefg
//abcdef
// 使用库函数strlen()计算字符串长度:头文件:# include <string.h>
//#include <string.h>
//
//int main()
//{
// int len = strlen("abc"); // ”abc\0“
// printf("%d\n",len);
//
// return 0;
//}
//// 3
// 使用转义字符进行进制转换:
# include <stdio.h>
//int main()
//{
// printf("%c\n",'\130'); // 130对应的ASCII码值:X
// printf("%d\n",'a'); // 97
// printf("%d\n",'A'); // 65
// printf("%d\n",'\x63'); // 99 :16进制的x63的ASCII码值为99
// printf("%c\n",'\x63'); // c 的ASCII码值为99
// printf("%c\n",'\x64'); // d
// return 0;
//}
/**选择语句和循环语句:**/
# include <stdio.h>
// 选择结构:
//int main()
//{
// int days = 0; // 变量必须赋值初始化
// printf("请输入骨折天数:");
// scanf("%d",&days); // 必须使用&来告知地址
// if (days >=90) :if()语句的条件放括号里面,下面语句用{}括起来
// {
// printf("可以脱拐了!");
// }
// else
// {
// printf("加油康复,胜利就在眼前!");
// }
//
// return 0;
//}
// 循环结构的:
//int main()
//{
// int days = 0; // 初始化变量
// while (days <= 90) // while(循环条件)
// { // {循环体}
// printf("骨折天数:%d\n",days);
// days++; // 自增
// }
// printf("可以脱拐啦!"); // 跳出循环后执行
//
// return 0;
//}
// 运行结果:
//骨折天数:0
//骨折天数:1
//骨折天数:2
//骨折天数:3
//......
//骨折天数:88
//骨折天数:89
//骨折天数:90
//可以脱拐啦!
//进程已结束,退出代码0
/**函数:实现一定的功能**/
// 求两个整数之和-不使用函数:
//int main()
//{
// int a = 0;
// int b = 0;
// scanf("%d %d",&a,&b);
// int sum = a+b;
// printf("%d\n",sum);
//
// return 0;
//}
// 使用函数:
//int Add(int x, int y) // 创建函数,参数为整型变量
//{
// int z = 0; // 初始化z // {函数体}:实现变量相加功能
// z = x + y;
// return z; // ⭐返回值z为int型,函数类型要定义为int
//
//}
// 此函数也可以简化为:
//int Add_1(int x, int y) // 创建函数,参数为整型变量
//{
// return (x+y); // ⭐返回值z为int型,函数类型要定义为int
//}
// 结合数学概念,此函数是个“相加机器”
// 编程中函数存在的意义:函数封装好之后可以直接调用,
// 避免重复写代码来实现固定功能,当函数的代码体量很大时,可以提高效率
// ⭐使用不同函数实现不同功能,有利于程序模块化,方便调试。
//int main()
//{
// int a = 0;
// int b = 0;
// scanf("%d %d",&a,&b);
//// int sum = a+b;
// int sum = Add(a,b); // ⭐使用定义好的函数:将x+y=z的值放入sum
//
// // 遇到求和问题时,直接调用此函数即可:
// int n1 = 2000;
// int n2 = 1000;
// int sum2 = Add(n1,n2);
// printf("%d\n", sum2);
//
// printf("%d\n",sum);
//
// return 0;
//}
/**数组:存放相同类型的有序序列**/
//int main()
//{
//int arr[10] = {10,11,12,13,14,15,16,17};
// 创建其它类型的数组:
//double d[5] = {3.0,1.2,0.6};
//char ch[20] = {'a','b','c'};
//// C语言还规定了数组元组的下标:0,1,2,3,4,n-1
//// 通过下标访问元素:arr[2]:访问元素12、arr[8]:访问第九个元素。
//
//// printf("%d\n",arr[6]);
//// 16
//
//// 遍历数组元素:
//// 从下标0开始访问
//int i = 0;
// // while循环遍历
// while (i<10)
// {
// printf("数组的第%d个元素为%d\n",i+1,i);
// // 访问完一个元素i自增1
// i = i + 1;
// }
// return 0;
//}
//数组的第1个元素为0
//数组的第2个元素为1
//数组的第3个元素为2
//数组的第4个元素为3
//数组的第5个元素为4
//...
//数组的第10个元素为9
/**C语言中的操作符:**/
// ①算术操作符:+、-、*、/、取模(余数)%。
//int main()
//{
// int a = 7;
// int b = 3;
// printf("%d\n",a/b); // 7/3:商2余1,结果为2
// printf("%d\n",a%b); // 7%3:商2余1,结果为1
// ps:当除号两端都为整数时,执行的是整数除法,只要有一个浮点数,执行的是浮点数除法
// 取模只能是整数。
// return 0;
//}
// 2
// 1
// ②移位操作符:二进制右移一位:>>、二进制右移一位:<<
// 规则:左移:左边舍弃,右边补零;
// 右移:右移运算分两种:
//1. 逻辑移位:左边用0填充,右边丢弃
//2. ==算术移位==:左边用原该值的符号位填充,右边丢弃
// 大多数编译器使用的是==算术移位==
// 参考链接:https://zhuanlan.zhihu.com/p/608346456
// ③位操作符:与&、异或^、或|
// ④赋值操作符:+=、-=、*=、/=、&=、^=、|=、右移等>>=、<<=
/*单目操作符:*/
//双目操作符:需要有两个操作数,如:a+b、a-b、a*b;
//单目操作符:只有一个操作数,如:!逻辑反操作、-负值、+正值、&取地址、
// sizeof操作数的类型长度(单位为字节)、~二进制按位取反、--前置、
// 后置--、++前置、后置++、*间接访问操作符号、(类型)强制类型转换。
// PS:C语言中,0表示假,非0表示真:
//int main()
//{
// int flag = 0;
// if (!flag) // 对假取反,表示真
// {
// printf("这是真的!");
// }
//
// return 0;
//}
//这是真的!
//int main()
//{
// int arr[] = {0, 1, 1, 1, 3, 4, 5};
// printf("%d\n", sizeof(arr));
//
// return 0;
//}
// 28
/*如果你的目标是计算整个数组占用的字节数,那么这段代码是没有问题的。
User
那为什么编译器会提示我将%d改为%lu
ChatGPT
如果你的编译器提示你将 %d 改为 %lu,那是因为 %d 用于打印有符号整数,
而 sizeof 返回的是无符号整数类型 size_t。在一些平台上,size_t 的大小可能
与 int 不同,因此编译器为了避免潜在的错误或警告,建议你使用 %lu
来匹配 size_t 的类型。
因此,你可以修改代码如下:
```c
//#include <stdio.h>
//
//int main() {
// int arr[] = {0, 1, 1, 1, 3, 4, 5};
// printf("%lu\n", sizeof(arr));
//
// return 0;
//}
/*`%lu` 是用来输出无符号长整型(unsigned long)的数据。
* 在 `printf` 函数中,格式说明符用于指定输出的数据类型。下面是一些常见的格式说明符:
- `%d`: 用于有符号整数(int)
- `%u`: 用于无符号整数(unsigned int)
- `%ld`: 用于有符号长整数(long)
- `%lu`: 用于无符号长整数(unsigned long)
在你的代码中,`sizeof(arr)` 返回的是 `size_t` 类型,它是无符号长整数。
因此,正确的格式说明符是 `%lu`。*/
```c
/*前置++、后置++、--:*/
//int main()
//{
// int a = 10;
// int b = a++; // 先使用a,后++,即:int b = a,a=a+1
// int c = ++a; // 先++,后使用,即:int a=a+1, c = a
//
// printf("%d,%d,%d",a,b,c);
//
// return 0;
//}
// 结果:
// 12,10,12
// 程序执行过程:
// a初始值为10,执行b=a++后,b=10、a = a+1;
// 此时a=11,b=10
// 执行c=++a后,即执行:a+1,c=11+1;
// 此时a=12,b=10,c=12
// 输出abc;
// return 0;程序执行完毕。