C语言学习笔记-入门篇02:初识C语言

42 阅读13分钟

前言:本篇文章主要涉及笔者学习的以下几个主题:

  1. 变量的作用域和生命周期:

    • 全局变量的作用域是整个工程,可以使用extern函数引用。
    • 展示了局部变量的生命周期,生命周期结束意味着程序执行结束。
  2. 常量和变量:

    • 使用const修饰常变量,展示了常量的属性。
    • 通过数组验证const修饰的变量本质上还是变量,不允许再被修改。
    • 使用#define定义标识符常量。
    • 枚举常量的创建和使用。
  3. 字符串:

    • 展示了字符和字符串的定义方式。
    • 介绍了字符串末尾默认以\0结尾的特性。
    • 使用库函数strlen()计算字符串长度。
  4. 使用转义字符进行进制转换:

    • 展示了一些使用转义字符进行进制转换的例子。
  5. 选择语句和循环语句:

    • 展示了简单的if-else结构和while循环结构。
  6. 函数:

    • 展示了函数的定义和调用,以及函数的作用。
    • 通过一个求两个整数之和的例子演示了函数的使用。
  7. 数组:

    • 展示了数组的定义和遍历。
  8. C语言中的操作符:

    • 包括算术操作符、移位操作符、位操作符、赋值操作符等。
  9. 前置++、后置++、--(新手容易困惑):

    • 展示了前置和后置递增/递减操作符的使用。

每个主题都有相应的代码示例,用于说明相关概念和语法。

主题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;程序执行完毕。

继续前进吧!