C语言学习笔记-入门篇04:基本概念、控制结构与输入输出

59 阅读12分钟

前言:本篇主要涉及C语言中常用的基本概念、控制结构、函数以及输入输出等方面的知识。

主要涵盖了以下主题:

  1. 宏定义:

    • 符号常量定义和使用。
    • 代码替换和宏的基本语法。
    • 宏在符号常量定义、代码替换、和条件编译方面的作用。
  2. 指针:

    • 指针的基本概念和使用。
    • 指针变量、解引用操作符、以及指针的大小。
  3. 结构体:

    • 结构体的定义和成员访问。
    • 使用结构体类型创建结构体变量。
    • 结构体指针的使用。
    • 嵌套结构体的定义。
    • 结构体数组的使用。
    • 使用 typedef 简化结构体声明。
  4. 分支语句(选择结构):

    • 基本的if-else分支结构。
    • 多分支和else if的使用。
    • 与分支相关的应用示例,如学生成绩录取系统。
  5. 循环语句:

    • while循环和for循环的基本用法。
    • 死循环和break、continue的应用。
    • 循环结构在奇数判断和输出特定范围奇数的应用。
  6. 输入输出函数:

    • getchar()和putchar()的基本用法。
    • 输入缓冲区的概念和处理方式。

宏定义

符号常量定义

#define MAX_SIZE 100

代码替换

#define SWAP(x, y) { int temp = x; x = y; y = temp; }

条件编译

#define DEBUG

自定义宏示例

#define ADD(x,y) ((x)+(y))

指针

int main() {
    int a = 10;
    int* p = &a;
}

结构体

定义结构体

struct Student {
    int id;
    char name[50];
    char sex[10];
    char tel[12];
};

使用结构体

struct Student s = {2023001,"张三","男","10086"};

结构体指针

void print(struct Student* ps){
    printf("%d %s %s %s\n", ps->id, ps->name, ps->sex, ps->tel);
}

嵌套结构体

struct Address {
    char street[50];
    char city[50];
    int zipCode;
};

struct Person {
    char name[50];
    int age;
    struct Address address;
};

结构体数组

struct Student class[5];

typedef 简化结构体声明

typedef struct {
    int hours;
    int minutes;
    int seconds;
} Time;

分支语句(选择结构)

基本分支

if (grade >= Grade_threshold) {
    // code
} else {
    // code
}

多分支

if (grade > 380)
    // code
else if (grade < 380 && grade > 370)
    // code
else if (grade < 370 && grade > 360)
    // code
else if (grade < 360)
    // code
else
    // code

循环语句

while循环

int num = 1;
while (num <= 10) {
    // code
    num++;
}

for循环

for (num = 0; num <= 100; num++) {
    // code
}

死循环

while (1) {
    // code
}

break和continue

while (num <= 10) {
    if (num == 5) {
        break;
    }
    // code
    num++;
}

while (num <= 10) {
    num++;
    if (num == 5) {
        continue;
    }
    // code
}

输入输出函数

getchar()和putchar()

char c;
printf("Enter a character: ");
c = getchar();
printf("You entered: ");
putchar(c);

输入缓冲区

清理输入缓冲区

getchar();

源代码:

#define 定义标识符常量·:  
//#define NUM 100 // 符号常量NUM代表100,在编译阶段NUM会被替换为100  
  
//#define 定义宏:(宏是有参数的):  
//在C语言中,`#define`是用来定义宏的预处理指令。宏是一种代码替换的技术,  
// 通过定义宏,你可以在程序中使用简单的标识符来表示一组代码,这组代码会在  
// 预处理阶段被替换成相应的内容。`#define`的基本语法如下:  
  
//#define 标识符 替换文本  
  
//例如,下面是一个简单的宏定义示例:  
//#define PI 3.14159  
//在这个例子中,`PI`是一个标识符,它被定义为`3.14159`。  
// 在程序中,每次出现`PI`时,都会被替换为`3.14159`。  
  
//宏的作用有以下几个方面:  
1. **符号常量定义:** 通过宏定义可以创建符号常量,这样可以在程序中使用  
有意义的标识符来代替一些常量值,使代码更易读,也更容易维护。  
  
#define MAX_SIZE 100  
这里,`MAX_SIZE`就代表了一个常量值100,方便在程序中使用。  
  
2. **代码替换:** 宏定义还可以用于替换一段代码。例如,你可以定义  
一个简单的宏来交换两个变量的值:  
  
#define SWAP(x, y) { int temp = x; x = y; y = temp; }  
在程序中使用这个宏可以实现变量交换的功能。  
int a = 5, b = 10;  
SWAP(a, b);  
上述代码在预处理阶段会被替换为:  
{ int temp = a; a = b; b = temp; }  
  
3. **条件编译:** 宏定义也经常用于条件编译,通过在编译时根据条件  
选择性地包含或排除某些代码块,可以实现不同平台或配置下的代码控制。  
  
#define DEBUG  
在调试阶段使用上述宏定义,然后可以通过条件编译选择是否包含调试代码。  
这只是宏的一些基础用法,宏在C语言中有更广泛的应用,但也需要注意一些潜  
在的问题,比如宏的副作用和作用域等。  
  
自己尝试使用宏定义:  
#define ADD(x,y) ((x)+(y)) // 宏定义ADD(x,y),宏体为(x)+(y)  
  
int main()  
{  
int x = 0, y = 0;  
printf("请输入要求和的数:\n");  
scanf("%d %d",&x,&y);  
int z = ADD(x,y); // 定义变量z来接收结果,使用宏定义替换(x)+(y)  
printf("求和结果为:%d",z);  
  
return 0;  
}  
结果符合预期:  
请输入要求和的数:  
1 2  
求和结果为:3  
  
指针:“内存单元中内存的编号,即地址,存放指针(地址)的变量:指针变量”  
int main()  
{  
int a = 10; // 向内存申请4个字节,存储10  
printf("这是变量a:%d",a);  
scanf("%d",&a); // &a:取地址,按照地址在内存中找到a  
int* p = &a; // 将a的地址指向指针变量p,p就是指针变量  
// * 表示p是指针变量,int 说明指针p指向的对象是整型  
// “指针变量就是用来存放地址的”  
// *:“解引用操作符,*p就是通过p中存放的地址找到所指向的对象,因此,  
// *p就是p指向的对象。”  
// 指针变量的大小取决于地址的大小  
  
return 0;  
}  
  
结构体:  
结构体是一种用户自定义的数据类型,用于“将不同类型的数据组合在一起,  
形成一个新的数据类型”。以下是关于C语言结构体的一些基本概念和用法:  
  
定义结构体  
struct Student { // 结构体:学生  
// 结构体成员:  
int id; // 学号  
char name[50];  
char sex[10]; // 性别  
char tel[12]; // 电话  
};  
  
int main(){  
  
// 使用结构体类型创建结构体变量s:(结构体类型不占空间,创建的变量才申请空间)  
// struct Student s  
// 给创建的结构体变量赋值(初始化):  
struct Student s = {2023001,"张三","男","10086"};  
// 通过“结构体对象.成员名”访问结构体成员:  
printf("%d %s %s %s\n",s.id,s.name,s.sex,s.tel);  
  
return 0;  
}  
//2023001 张三 男 10086  
  
// 使用结构体指针访问结构体成员:  
void print(struct Student* ps){ // 定义结构体类型指针ps  
  
// 使用“(*指针名).成员名访问结构体成员:  
printf("%d %s %s %s\n",(*ps).id,(*ps).name,(*ps).sex,(*ps).tel);  
// 使用“->”表示ps指向的对象(Student)的成员:  
printf("%d %s %s %s\n",ps->id,ps->name,ps->sex,ps->tel);  
}  
  
  
GPT:  
// 使用上面定义好的的结构体“类型”创建结构体变量  
struct Student student1;  
  
// 初始化结构体变量  
student1.id = 1;  
strcpy(student1.name, "John Doe");  
student1.gpa = 3.8;  
  
// 结构体作为函数参数  
void printStudent(struct Student s) {  
printf("ID: %d\n", s.id);  
printf("Name: %s\n", s.name);  
printf("GPA: %.2f\n", s.gpa);  
}  
  
// 调用函数  
printStudent(student1);  
  
// 结构体指针  
struct Student *ptrStudent = &student1;  
  
// 通过指针访问结构体成员  
printf("ID: %d\n", ptrStudent->id);  
printf("Name: %s\n", ptrStudent->name);  
printf("GPA: %.2f\n", ptrStudent->gpa);  
  
// 嵌套结构体  
struct Address {  
char street[50];  
char city[50];  
int zipCode;  
};  
  
struct Person {  
char name[50];  
int age;  
struct Address address;  
};  
  
// 结构体数组  
struct Student class[5];  
  
// 初始化结构体数组  
class[0].id = 1;  
strcpy(class[0].name, "Alice");  
class[0].gpa = 3.5;  
// 同样的方式初始化其他数组元素  
  
// 使用 typedef 简化结构体声明(结构体关键字)  
typedef struct {  
int hours;  
int minutes;  
int seconds;  
} Time;  
  
分支语句(选择结构):  
int main(){  
  
int grade = 0; // 初始化初试成绩  
int grade_t = 0; // 初始化复试成绩  
int Grade_threshold = 388; // 初始化分数线  
int Line_for_re_examinatio = 399; // 初始化复试线  
  
printf("考生您好,欢迎来到长安大学研究生录取系统!\n请按照提示输入您的成绩!");  
printf("请输入您的初试成绩:");  
scanf("%d",&grade);  
  
if (grade >= Grade_threshold)  
{  
printf("恭喜你成功进入复试!");  
}  
else  
{  
printf("很遗憾,您未进入复试。");  
}  
  
printf("请输入您的总成绩:\n");  
scanf("%d",&grade_t);  
  
if (grade_t >= Line_for_re_examinatio)  
{  
printf("恭喜你已被长安大学录取!");  
}  
else  
{  
printf("很遗憾,您未被录取。");  
}  
  
return 0;  
}  
结果符合预期:  
考生您好,欢迎来到长安大学研究生录取系统!  
请按照提示输入您的成绩!请输入您的初试成绩:401  
恭喜你成功进入复试!请输入您的总成绩:  
421  
恭喜你已被长安大学录取!  
  
选择结构2else if:多分支:“可以实现多条件判断”  
  
int main()  
{  
int grade = 0;  
printf("请输入您的成绩:");  
scanf("%d",&grade);  
  
if (grade > 380)  
printf("苍天不负有心人,恭喜你上岸啦!");  
else if (grade < 380 && grade > 370)  
printf("加油,还有机会!");  
else if (grade < 370 && grade > 360)  
printf("希望还是有的。");  
else if (grade < 360)  
printf("莫等闲,白了少年头,空悲切!");  
else  
printf("请反省自己,是不是努力了!");  
  
return 0;  
}  
  
else 只跟最近的if匹配成对,不是按照缩进匹配:  
  
int main()  
{  
int a = 0, b = 1;  
if (a == 1) // 条件不满足,下面的代码块不执行,直接结束  
{ if (b == 2)  
printf("hell0\n");  
else // 这个else是跟 if (a == 1)匹配的  
printf("hi\n");  
}  
return 0;  
}  
  
奇数判断:  
int main()  
{  
int num = 0;  
printf("请输入您要判断的整数:");  
scanf("%d",&num);  
if (num % 2 == 1) // num对2取模,商x余y,若余1,则模为1,则为奇数  
// 易错:(num % 2 = 1):把等与写成赋值  
printf("这是个奇数");  
else  
printf("这是个偶数");  
  
return 0;  
}  
  
输出1-100之间的奇数:  
int main()  
{  
int num = 0; // 初始化num  
for (num = 0; num <= 100; num++) // 生成1-100之间的数  
{  
if (num % 2 == 1)  
printf("%d\n",num);  
}  
return 0;  
}  
  
while循环版本:  
int main()  
{  
int i = 1; // 初始化变量i  
while (i <= 100) // 循环条件  
{  
if (i % 2 == 1) // 判断奇数  
printf("%d",i); // 输出奇数  
i++; // 一轮判断结束,继续判断下一个数,若不自增,i不会>100,循环无法结束  
// 将会一直打印1  
}  
  
return 0;  
}  
  
循环语句:  
while循环:while(表达式){循环体};表达式为真,则进入循环体,直到表达式为假。  
int main()  
{  
while (1) // 非0即为真,这是一个死循环。  
{  
printf("hhh");  
}  
  
return 0;  
}  
  
使用while循环打印1-10int main(){  
  
int num = 1;  
while (num <= 10)  
{  
printf("%d", num);  
num++;  
}  
return 0;  
}  
  
复习breakcontinueint main(){  
  
int num = 1;  
while (num <= 10)  
{  
if (num == 5)  
{  
break;  
}  
printf("%d", num);  
num++;  
}  
return 0;  
}  
1234  
  
int main(){  
  
int num = 1;  
while (num <= 10)  
{  
num++;  
if (num == 5)  
{  
continue;  
}  
printf("%d", num);  
  
}  
return 0;  
}  
23467891011  
  
getchar()和putchar():  
getchar()和putchar()是两个常用的输入输出函数,用于从标准输入读取字符和向标准输出写入字符。它们的作用如下:  
  1. getchar():
  • getchar() 用于从标准输入(通常是键盘)读取一个字符。
  • 返回值是读取的字符的ASCII码值,或者在文件结束时返回 EOF(End of File)。

示例:

#include <stdio.h>  
  
int main() {  
char c;  
printf("Enter a character: ");  
c = getchar(); // 从标准输入读取一个字符  
printf("You entered: ");  
putchar(c); // 将字符输出到标准输出  
return 0;  
}  
  1. putchar():
  • putchar() 用于向标准输出(通常是屏幕)写入一个字符。
  • 接受一个整数参数,通常是表示字符的ASCII码值。
  • 返回写入成功的字符,或者在错误时返回 EOF

示例:

#include <stdio.h>  
  
int main() {  
char c = 'A';  
printf("The character is: ");  
putchar(c); // 将字符输出到标准输出  
return 0;  
}  

这些函数在实际编程中经常用于简单的字符输入和输出。请注意,
它们通常在控制台程序中使用,而在图形用户界面(GUI)程序或其他环境中
可能会使用不同的输入输出函数。

在理解 getchar() 和输入缓冲区的关系时,需要了解C语言中的输入缓冲区概念。

输入缓冲区:
输入缓冲区是一个存储用户输入的地方,它存储了键盘输入的字符,等待程序读取。当用户在键盘上输入一串字符,这些字符首先被存储在输入缓冲区中,然后由程序从缓冲区中读取。

getchar() 相关的输入缓冲区:
getchar() 函数从标准输入(通常是键盘)读取一个字符,并且它会从输入缓冲区中读取一个字符。这就涉及到一个重要的概念,即缓冲区的使用。

当你调用 getchar() 时,它会检查输入缓冲区。如果输入缓冲区非空(有待读取的字符),getchar() 会直接从缓冲区中读取一个字符并返回。如果输入缓冲区为空,getchar() 会等待用户输入,并且直到用户按下 Enter 键,输入的字符才会被存储到输入缓冲区。然后,getchar() 从输入缓冲区中读取一个字符并返回。

这种行为可能导致一些不直观的结果,特别是当你在程序中组合使用不同的输入函数时。如果在使用 scanf() 或其他输入函数时留下了换行符(Enter 键)在输入缓冲区中,它可能会影响到后续的 getchar() 调用。为了避免这种情况,你可以在使用 getchar() 之前清理输入缓冲区,可以使用 getchar()scanf("%*c") 来处理换行符。

下面是一个简单的例子,演示了 getchar() 与输入缓冲区的交互:

#include <stdio.h>  
  
int main() {  
char c;  
  
printf("Enter a character: ");  
c = getchar(); // 从输入缓冲区中读取一个字符  
  
printf("You entered: ");  
putchar(c); // 将字符输出到标准输出  
  
return 0;  
}  
 
  
在这个例子中,`getchar()` 会等待用户输入,并且用户按下 Enter 键后,输入的字符被读取并存储在变量 `c` 中。  
  
int main() {  
char c;  
  
printf("请输入字符: ");  
c = getchar(); // 从输入缓冲区中读取一个字符  
  
printf("您的输入为: ");  
putchar(c); // 将字符输出到标准输出  
  
return 0;  
}  
请输入字符: a  
您的输入为: a

继续前进吧!

参考链接:link.juejin.cn/?target=htt…