C语言基础
大一曾经的工作室招新题C语言部分
1. A+B problem
程序为什么要被编译后才能运行
计算机无法直接理解或执行源代码,因为它包含了高级语言中的抽象概念,而计算机只能理解机器语言指令,即由二进制数字组成的指令代码。编译器是一种程序,负责将源代码转换为目标代码,这是一种特定计算机体系结构可以直接执行的代码。目标代码通常是二进制文件,它包含了程序的指令和数据,可以由计算机的处理器执行。
#include是什么意思,为什么不实现scanf和printf就能使用,如何调用到的#include是一个预处理指令,用于将指定的文件内容包含到源代码中。它通常用来包含头文件(header files),头文件中包含了函数的声明、宏定义和数据结构等信息。预处理器会将指定的头文件内容插入到当前源代码文件的相应位置。这样,你就能够在代码中使用头文件中定义的函数和数据结构,而不必手动复制头文件的内容到每个源文件中。scanf()和printf()这两个函数,它们是C语言标准库(Standard Library)中定义的输入输出函数。标准库是一组预先编写好的函数,提供了各种常用的功能,包括输入输出、字符串处理、数学计算等。这些函数的定义和实现通常存储在标准库的头文件中,例如<stdio.h>通过
#include <stdio.h>,你可以在程序中包含标准输入输出函数的声明,这样编译器就知道这些函数的原型,而链接器会将它们与标准库中的实现链接在一起,使得你可以在程序中调用它们。argc,agrv分别是什么意思,编写代码实现倒序打印命令行输入参数的功能在C语言中,
argc和argv是命令行参数传递的一种方式。它们通常在程序的main函数中使用。argc(argument count)表示命令行参数的数量,是一个整数。argv(argument vector)是一个指针数组,其中每个元素是一个指向传递给程序的命令行参数的指针。
1
2
3
4
5
6
7
8
int main(int argc, char *argv[])
{
for (int i = argc - 1; i > 0; i--) {
printf("%s ", argv[i]);
}
return 0;
}//在命令行中输入:"可执行文件路径 arg1 arg2 arg3 "输出:" arg3 arg2 arg1"主函数也能是
void吗 主函数返回值有什么意义主函数(
main函数)的返回类型通常是int,表示该函数可以返回一个整数值。这个整数值通常用于指示程序的执行状态,返回给操作系统。一般约定,返回值为0表示程序成功执行,非零值(通常是其他整数)表示程序执行出现错误或异常终止。在一些特定的编译器中,你可以使用
void作为main函数的返回类型。void main()并不是标准C语言的写法,不推荐使用。在标准C中,main函数的返回类型应该是int。main函数是程序的入口点(entry point),是程序执行的起始位置。当你运行一个C或C++程序时,操作系统会调用main函数来启动程序的执行。main函数通常是第一个被调用的函数。程序的执行流程从main函数开始,然后按照在main函数内部的代码顺序依次执行。在main函数内部,你可以调用其他函数、定义变量、执行各种操作,控制程序的逻辑和流程。当
main函数内部的所有代码执行完毕,程序会自动返回一个整数值(通常是0),表示程序的退出状态。在这个时候,main函数可以被认为是最后一个执行的函数。当main函数返回后,程序的执行结束,操作系统会收到程序的退出状态。在
main函数之前,编译器和操作系统可能会进行一些初始化工作,例如初始化全局变量、分配内存等。在main函数之后,程序的资源会被释放,例如关闭文件、释放内存等。&符号是什么意思
&符号是”取地址运算符”。它用于获取变量的内存地址,即变量在计算机内存中的位置。当你使用&符号后跟一个变量名时,它会返回该变量的地址。&符号还有一个常见的用法,它可以表示”按位与”运算。在这种情况下,&表示两个二进制数进行按位与运算,返回一个新的二进制数。
例如,对于整数
a和b,a & b执行按位与运算,即将a和b的二进制表示中对应位上的值进行与操作。如果两个对应位上的值都为 1,则结果的对应位为 1,否则为 0。1
2
3
4int a = 5; // 二进制表示:0101
int b = 3; // 二进制表示:0011
int result = a & b; // 按位与运算结果:0001,即十进制的 1- c++中&还能声明一个引用
实现一百位整数加法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33//这里是用cpp写的
using namespace std;
int maxm=10001;
int main()
{
int numa[maxm]; int numb[maxm]; int leng_a,leng_b;
string a,b,temp;
cin>>a>>b;
leng_a=a.length();leng_b=b.length();
if (leng_a<leng_b)
{
temp=a;
a=b;
b=temp;
swap(leng_a,leng_b);
}
for (int i=0;i<leng_a;i++) numa[i]=a[leng_a-i-1]-'0';
for (int i=0;i<leng_b;i++) numb[i]=b[leng_b-i-1]-'0';
int l=max(leng_a,leng_b);
for (int i=0;i<l;i++)
{
if ((numa[i]+numb[i])>=10)
numa[i+1]++;
numa[i]=(numa[i]+numb[i])%10;
}
if(numa[l]>0) l=l+1;
for (int i=l-1;i>=0;i--) cout<<numa[i];
return 0;
}
//高精度加法a+b,例如输入99999999999999 1234567890 输出100001234567889printf为什么可以接受变长参数printf函数之所以能够接受不定数量的参数,是因为它是使用可变参数(variable arguments)实现的。在C语言中,可变参数的处理是通过<stdarg.h>头文件中的函数提供的。在
printf函数中,格式字符串中的格式化占位符(例如%d,%s等)指定了应该接受的参数类型和数量。C语言的<stdarg.h>头文件提供了一组宏和函数,例如va_list,va_start,va_arg, 和va_end,用于处理可变参数的传递和访问。具体步骤如下:
va_list类型用于存储可变参数的信息。va_start宏初始化va_list对象,使其指向参数列表的第一个可变参数。va_arg宏用于按照指定类型获取参数列表中的参数值。va_end宏用于清理va_list对象。
printf函数内部使用了这些宏和函数,根据格式化字符串中的占位符,逐个获取传递给printf的参数值,然后按照格式化字符串的格式输出这些值。这种可变参数的处理机制使得
printf可以接受不同数量和类型的参数,并且根据格式化字符串进行相应的处理。这样,你可以在使用printf函数时传递不同数量的参数,而printf函数会根据格式化字符串进行适当的格式化和输出。
2. 计算机原理 int 2 Binary
整数在计算机中怎么储存
以补码存储,其中正整数和
0的原码补码反码都相等,负数反码为原码除符号位的0变1,1变0,补码为反码加1.写出
0 99 -99的二进制补码0的补码为00000000,99的为01100011,-99的为10011101。
//实现一个函数 #include<stdio.h> #include<stdlib.h> char *int2binary(int num){ char* p_str = (char*)malloc(8*sizeof(char)); for(int i=0;i<8;i++){ p_str[i]='0'; } if(num<0){ num=256+num; } int i=0; while(num>0&&i<8){ p_str[i]=(char)(num%2+48); num=num/2; i++; } return p_str; } int main(){ int num; char *p_str=NULL; while(1){scanf("%d",&num); p_str=int2binary(num); for (int i=8;i>0;i--){ printf("%c",p_str[i-1]); } } return 0; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
- 小数在计算机的储存
整数位和小数位转化为二进制数后使用符号位,指数位,尾数位储存,可以写成
$$
num=(-1)^s\times1.b\times2^c
$$
其中`s`为符号位数,`b`为尾数,`c`为指数。例如`float`类型为1位符号位8位指数位,23位尾数位,且当指数位全为0或1时可以表示特殊值,例如无穷大或`0`或`NaN`.
## 3. 文件
- 什么是文件?什么是流?区别?
- 文件是对I/O设备的抽象,是字节序列,每个I/O设备都可以看成文件。(csapp)
文件是计算机上存储数据的一种方式,通常以命名的方式存储在存储设备(比如硬盘、固态硬盘、光盘等)上。文件可以包含文本、图像、音频、视频等各种类型的数据。每个文件都有一个唯一的文件名和文件路径,用于在文件系统中标识和定位文件。
- 流是一个抽象的概念,用于表示数据的序列,这些数据可以是字节、字符或其他类型的数据单元。流可以是输入流(用于读取数据)或输出流(用于写入数据)。流的主要目的是提供一种连续、有序的数据访问方式,而不需要事先知道数据的全部内容。
- 区别:
1. **存储方式**:
- 文件是数据在存储设备上的持久化表示,以命名的方式存储。
- 流是对数据的抽象,表示数据的顺序传输,可以与各种数据源交互。
2. **数据处理方式**:
- 文件通常需要一次性读取或写入。
- 流通常支持逐个或逐批次读取/写入,适合处理大量数据或网络通信等场景。
3. **灵活性**:
- 流提供了更灵活的数据处理方式,可以逐个或逐批次处理数据,适用于各种场景。
- 文件通常用于存储和传输较大量的数据,对于逐个或逐批次处理数据较为麻烦。
- 实现HaveAlookAt命令
```c
#include <stdio.h>
int main(int argc,char *argv[]) {
char ch;
FILE *file;
file = fopen(argv[1], "r");
// 检查文件是否成功打开
if (file == NULL) {
printf("无法打开文件 %s\n", argv[1]);
return 1;
}
// 读取并显示文件内容
printf("文件内容:\n");
while ((ch = fgetc(file)) != EOF) {
printf("%c", ch);
}
// 关闭文件
fclose(file);
return 0;
}实现move to命令
1
2
3
4
5
6
7
8
9
10
11
12
int main(int argc,char *argv[]) {
char source_path[] = argv[1];
char destination_path[] =argv[2];
// 将文件从源路径移动到目标路径
if (rename(source_path, destination_path) == 0) {
printf("文件移动成功。\n");
} else {
perror("文件移动失败");
}
return 0;
}
4. 循环链表
#include<stdio.h> #include<stdlib.h> #include<stdbool.h> struct ListNode{ int val; bool pass_by; struct ListNode *next; }; struct ListNode *BuiltNode[10000]; int BuiltNumber=-1; bool hasCycle(struct ListNode *head){ while(head->next!=NULL){ if(head->next->pass_by==true) return true; head->pass_by=true; head=head->next; } return false; } struct ListNode *buildlist(struct ListNode *lastnode,struct ListNode *nextdir,int val){ struct ListNode *newnode=(struct ListNode*)malloc(sizeof(struct ListNode)); newnode->next=nextdir; if(lastnode==NULL){ BuiltNumber++; BuiltNode[BuiltNumber]=newnode; printf("生成节点%d\n",BuiltNumber+1); return newnode; } if(val!=-1) newnode->val=val; newnode->pass_by=false; lastnode->next=newnode; BuiltNumber++; BuiltNode[BuiltNumber]=newnode; printf("生成节点%d\n",BuiltNumber+1); return newnode; } int main(){ for(int i=0;i<100;i++){ BuiltNode[i]=NULL; } struct ListNode *head=NULL; struct ListNode *lastnode=NULL; int val; scanf("%d",&val); head=buildlist(head,NULL,val); lastnode=head; for(int i=0;i<9999;i++){ struct ListNode *nextdir=NULL; int NextNodeNumber; printf("请输入下一个节点的节点数和值\n"); scanf("%d%d",&NextNodeNumber,&val); if(NextNodeNumber>100){ printf("错误输入,请重新输入\n"); i--; continue; } nextdir=BuiltNode[NextNodeNumber-1]; lastnode=buildlist(lastnode,nextdir,-1); if(nextdir!=NULL){ printf("找到了环,连接到了第%d个节点\n",NextNodeNumber); break; } } BuiltNumber=0; bool flag=hasCycle(head); printf("%d\n",flag); return 0; }例如:输入:1 1 -1 -1 -1 -1 2 1 1 1 1 1 3 0 0 0 0 0 得到的文件内容为: 1宿舍的1床的意愿为Yes 1宿舍的2床的意愿为Yes 1宿舍的3床的意愿为Yes 1宿舍的4床的意愿为Yes 1宿舍状态由关灯变成开灯 2宿舍的1床的意愿为All 2宿舍的2床的意愿为All 2宿舍的3床的意愿为All 2宿舍的4床的意愿为All 宿舍状态不变 3宿舍的1床的意愿为No 3宿舍的2床的意愿为No 3宿舍的3床的意愿为No 3宿舍的4床的意愿为No 3宿舍状态由开灯变成关灯1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
## 5. 结构化
- ```c
#include<stdio.h>
#include<stdlib.h>
#define error 1000001
typedef int HumanWilling;
typedef int state;
enum openwilling{Yes=-1,No,All};
enum lightstate{open=0,shut};
struct Dorm
{
HumanWilling DormMember[4];
state LightState;
struct Dorm *FrontDorm;
struct Dorm *NextDorm;
int DormNumber;
int Open_qua,Shut_qua;
};
struct Dorm *LastDorm=NULL;
struct Dorm *SearchDir_dorm(int dormnumber){//查找宿舍号为dormnumber的宿舍并返回其地址
static struct Dorm* Justdir_dorm=NULL;//记录上一次访问的宿舍号从上次开始查找
struct Dorm *presentdorm;
if(Justdir_dorm!=NULL&&Justdir_dorm->DormNumber>dormnumber){
presentdorm=Justdir_dorm;
while(presentdorm->FrontDorm!=NULL){
presentdorm=presentdorm->FrontDorm;
if(presentdorm->DormNumber==dormnumber){
Justdir_dorm=presentdorm;
return presentdorm;
}
}
}
if(Justdir_dorm==NULL)
presentdorm=LastDorm;//第一次查询,从第一个含数据的节点开始
else if(Justdir_dorm->DormNumber<=dormnumber)
presentdorm=Justdir_dorm;
do{
if(presentdorm->DormNumber==dormnumber){
Justdir_dorm=presentdorm;
return presentdorm;
}
presentdorm=presentdorm->NextDorm;
}while(presentdorm!=NULL);
return NULL;
}
void BuildDormList(int dormnumber,state lightstate){//建立宿舍的链表,新宿舍连接到最后一个宿舍后,宿舍号按升序排列
if(LastDorm->DormNumber>=dormnumber||(lightstate!=0&&lightstate!=1)){
printf("输入的宿舍参数有误,建立失败\n");
return;
}
struct Dorm *nextdorm=(struct Dorm *)malloc(sizeof(struct Dorm));
nextdorm->DormNumber=dormnumber;
nextdorm->LightState=lightstate;
nextdorm->Open_qua=nextdorm->Shut_qua=0;
int willing;
for(int member=0;member<4;member++){
while(1){
printf("输入第%d床的意愿,Yes:-1 No:0 All:1\n",member+1);
scanf("%d",&willing);
if(willing>1||willing<-1){
printf("请正确输入\n");
continue;
}
break;
}
nextdorm->DormMember[member]=willing;
}
LastDorm->NextDorm=nextdorm;
nextdorm->FrontDorm=LastDorm;
LastDorm=nextdorm;
LastDorm->NextDorm=NULL;
}
HumanWilling CheckWilling(int member,struct Dorm *dir_dorm){//查询目标宿舍的目标成员的意愿
if(dir_dorm!=NULL)
return dir_dorm->DormMember[member];
return error;
}
state CheckLightState(struct Dorm *dir_dorm){//查询目标宿舍的关灯状态
if(dir_dorm!=NULL)
return dir_dorm->LightState;
return error;
}
int WriteIntoFile(struct Dorm *dir_dorm,int turn){//写入文件
FILE *file = fopen("D:\\test\\test100\\abcde.txt", "a+");
if (file == NULL) {
printf("无法打开文件。\n");
return error;
}
for(int i=1;i<=4;i++){
if(dir_dorm->DormMember[i-1]==Yes)
fprintf(file, "%d宿舍的%d床的意愿为Yes\n",dir_dorm->DormNumber,i);
else if(dir_dorm->DormMember[i-1]==No)
fprintf(file, "%d宿舍的%d床的意愿为No\n",dir_dorm->DormNumber,i);
else if(dir_dorm->DormMember[i-1]==All)
fprintf(file, "%d宿舍的%d床的意愿为All\n",dir_dorm->DormNumber,i);
}
if(turn==0)
fprintf(file,"%d宿舍状态由开灯变成关灯\n",dir_dorm->DormNumber);
else if(turn==1)
fprintf(file,"%d宿舍状态由关灯变成开灯\n",dir_dorm->DormNumber);
else
fprintf(file,"宿舍状态不变\n");
printf("数据已成功写入文件。\n");
return 0;
}
void TurnLightState(struct Dorm *dir_dorm){//改变关灯状态并写入文件
if(dir_dorm!=NULL){
for(int i=0;i<4;i++){
if(CheckWilling(i,dir_dorm)==Yes)
dir_dorm->Open_qua++;
if(CheckWilling(i,dir_dorm)==No)
dir_dorm->Shut_qua++;
}//统计意愿
if(CheckLightState(dir_dorm)==open&&dir_dorm->Shut_qua>=2){
dir_dorm->LightState=shut;
dir_dorm->Open_qua=dir_dorm->Shut_qua=0;
WriteIntoFile(dir_dorm,0);
return;
}
if(CheckLightState(dir_dorm)==shut&&dir_dorm->Open_qua>=3){
dir_dorm->LightState=open;
dir_dorm->Open_qua=dir_dorm->Shut_qua=0;
WriteIntoFile(dir_dorm,1);
return;
}
WriteIntoFile(dir_dorm,-1);//改变状态并写入文件
return;
}
printf("没有此宿舍\n");
return;
}
int main(){
struct Dorm* Dir_dorm=NULL;
struct Dorm *FirstDorm=NULL;//不存储真正的宿舍数据
FirstDorm=(struct Dorm *)malloc(sizeof(struct Dorm));
LastDorm=FirstDorm;
LastDorm->DormNumber=0;
int dormnumber,lightstate;
int i=0;
while(i<3){
scanf("%d%d",&dormnumber,&lightstate);
BuildDormList(dormnumber,lightstate);
i++;
}
LastDorm=FirstDorm->NextDorm;
LastDorm->FrontDorm=NULL;
free(FirstDorm);
i=0;
while(i<3){
scanf("%d",&dormnumber);
Dir_dorm=SearchDir_dorm(dormnumber);
TurnLightState(Dir_dorm);
i++;
}//简单的测试,可以更改地更复杂
return 0;
}