从零开始学习c语言

常用快捷键:

image-20221117014701069

除html与php外其他多少和c语言沾边

image-20221117021453185

一些概念:

image-20221117021840466

image-20221117021912231

image-20221117024217615

容量转换

image-20230104162014072

浮点数的储存形式

image-20230104175053588

二进制:1. 10进转2进(小数有精度要求)

image-20221115222016901

整数自下而上,小数自下而上

自己做了个二进制

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
//jsut a sudden spark for fun.(for int number)
#include <stdio.h>
#include <math.h>
int i=10000;
int main(){
char option;
printf("Please choose the option you want:\n'B'for decimal to binary\n'D'for binary to decimal\n");
scanf("%c",&option);
if(option=='B'){
long long int n;
long int j=0;
printf("Please input an integer\n");
scanf("%lld",&n);
int number[i];
while(n!=0){

number[j]=n%2;
n/=2;
j++;

}
long int x=j-1;
for(x;x>=0;x--)
printf("%d",number[x]);
}
if(option=='D'){
unsigned long long m=0;
int b=10;
int number[i];
int z=0;
printf("Please input a binary number\n");
scanf("%llu",&m);
while(m!=0){
number[z]=m%b;
m/=b;
z++;


}
long long sum=0;
int y=0;
for(y;y<z;y++){
sum+=number[y]*pow(2,y);
}
printf("%lld",sum);
}
}

数据太大了hold不住了·怎么办?

(关于我睡了一觉突然灵光一现了,我们十进制转二进制用数组储存超20位的数据,那么我们二进制转十进制

不就可以用数组读入一个超20位的数据吗?)

升级版(待改进)

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
#include <stdio.h>
#include <math.h>
int i=10000;
int main(){
char option;
printf("Please choose the option you want:\n'B'for decimal to binary\n'D'for binary to decimal\n");
scanf("%c",&option);
if(option=='B'){
long long int n;
long int j=0;
printf("Please input an integer\n");
scanf("%lld",&n);
int number[i];
while(n!=0){

number[j]=n%2;
n/=2;
j++;

}
long int x=j-1;
for(x;x>=0;x--)
printf("%d",number[x]);
}
if(option=='D'){
int number[i];
int z=0;
int ret=1;
printf("Please input a binary number,then input a letter to stop\n");
do{
ret=scanf("%1d",&number[z]);
++z;
}while(ret==1);
long long sum=0;
int y=z-2;
int j=0;
for(y,j;y>=0,j<z-1;y--,j++){
sum+=number[y]*pow(2,j);
}
printf("%lld",sum);
}
return 0;
}

image-20221118232030474

这是学长和老师给出的解释()明天试试

[^已用字符串数组解决,代码放在answer了]:

用补码。

image-20221116005548142

补码怎么求?

image-20221117003141327

八进制

image-20221117004034441

十六进制

image-20221117004527624

比武大会的一个不错的题目:

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
#include <stdio.h>
#include <stdlib.h>
#define N 65 //增加一个字符用来放标识符,便于判断。
long long myPow(int a,int x);
int main()
{
char str[N]={0},i=0; //str初始化为空字符,下标计数i不会超过N,所以用char类型就可以,用int当然也可以。
long long sum=0; //这里为什么不能用int?
while((str[i++]=getchar())!='\n') //先不考虑用户在中途输入非法字符的情况,如果需要考虑的话就需要增加判断条件
if(i==N) break;//做边界判断
str[i-1] = '\n'; // str[i-1]读到的是'\n',或者i为N的时候,str[i-1]也超出64个字符,这时也强行赋值为'\n',逻辑就一致。等学了字符串之后,我们会强行赋值为'\0'
if(str[0]=='0') //这时str[0]是最高位为符号位
for(int j=0;str[j]!='\n';j++)
{
if(str[j]=='1')
if((i-2)-j>=0) //这个判断不要也没问题,要了是为了更好读。
sum+=myPow(2,(i-2)-j);//有效元素的下标是i-2,因为str[i-1]=='\n'
}//这个大括号不能省略,否则后面那个else会匹配到这个if,我在讲选择结构时详细说明了原因。

else if(str[0]=='1') //这时str[0]也就是符号位为1为负数的补码
{
for(int j=1;str[j]!='\n';j++) //这时str[0]上的1是符号位,从次高位开始不为1的数据为真实数据,因为负数的补码前面再多的1都不影响结果
{
if(str[j]=='0') //补码是怎么来的?是符号位为1,其他位为对应的正数原码取反再+1得到的;补码的本质是从0减下来的,0-1得到的是-1的补码、0-2得到的是-2的补码;
if((i-2)-j>=0) //这判断可以不要,不影响逻辑和结果
sum+=myPow(2,(i-2)-j);
}
sum= -(sum+1); //因为是原码取反后再加1得到的,这里也需要加1再取相反数。注意按位取反和取相反数是不同的计算。
}
else //如果字符数组得到的第一个元素就是换行符或者是0或1之外的字符,说明用户没有输入过数字或者第一个字符就输入了非法的字符
{
printf("No number\n");//用户的输入不是有效输入
exit(0); //程序退出
}
printf("decimal=%lld\n",sum);
return 0;
}

long long myPow(int a,int x)
{
long long powNum=1;//powNum会参与乘积的计算,先赋初值为1;如果这个变量需要做累加计算的话,就要先赋值为0.
for(int i=1;i<=x;i++) //如果形参接收的x为0,这个循环不执行,返回的powNum是1
powNum *= a;
return powNum;
}

gets,gets_s,fgets之间的区别。

换行符的处理:

  1. gets会将最后的’\n’改成’\0’,gets_s会把最后的’\n’直接丢弃,fgets直接读取’\n’
  2. gets_s会将未读取的数据直接清空(为了读取数据不出幺蛾子),而fgets会保留未读取的部分,gets如果数据越界了会将不属于他的数据给覆盖,有很大的安全隐患。
  3. fgets的使用:char *fgets(char *restrict _Buf, int _MaxCount, FILE *restrict _File)

粒子:

a=20;

char[a];

fgets(a,20,stdin);(stdin从用户那里读入数据,如果这里是文件名的话那么从文件读取数据)

补充:

stdin与stdout:stdin是标准输入流,是标准输出流,类似于scanf与printf。(升级版plus)

逗号表达式

image-20230104175624280

普通运算

image-20230104181322654

运算符优先级:

image-20230104182033272

如何求复杂表达式的值?

image-20230104182619562

位运算:

相关运算符

image-20230104184148208

1.(可以升级之前的一些操作,比如说判断奇偶数,按位与会更快一点)

只要有0就是0

image-20230104184629199

2.只要有一就是一image-20230104185352538

3.正常性取向()

image-20230104185833513

4.按位左移与按位右移在没有溢出的条件下分别对应乘了2的n次方

image-20230105100211093

(绷不住了,寒假白兰到还有17天)

结构体

(1)结构体内存分配原则:

  • 原则一:结构体中元素按照定义顺序存放到内存中,但并不是紧密排列。从结构体存储的首地址开始 ,每一个元素存入内存中时,它都会认为内存是以自己的宽度来划分空间的,因此元素存放的位置一定会在自己大小的整数倍上开始。
  • 原则二: 在原则一的基础上,检查计算出的存储单元是否为所有元素中最宽的元素长度的整数倍。若是,则结束;否则,将其补齐为它的整数倍。

(2)定义位域时,各个成员的类型最好保持一致,比如都用char,或都用int,不要混合使用,这样才能达到节省内存空间的目的。

sscanf与sprintf语法

scsanf():

1
2
3
4
5
6
7
8
9
10
11
12
13
//昨天练习题目的参考答案:
#include <stdio.h>
void main()
{
double sum=0,num1,num2;
char a[]="123.45 456.78";
char b[30]={0};
{sscanf(a,"%lf%lf",&num1,&num2);}
sum=num1+num2;
sprintf(b,"sum=%f",sum);
puts(b);
}

描述

C 库函数 int sscanf(const char *str, const char *format, …) 从字符串读取格式化输入。

声明

下面是 sscanf() 函数的声明。

1
int sscanf(const char *str, const char *format, ...)

实例

下面的实例演示了 sscanf() 函数的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
int day, year;
char weekday[20], month[20], dtm[100];

strcpy( dtm, "Saturday March 25 1989" );
sscanf( dtm, "%s %s %d %d", weekday, month, &day, &year );

printf("%s %d, %d = %s\n", month, day, year, weekday );

return(0);
}

高级用法

1
2
3
4
5
char str[32] = "";

sscanf("123456abcdedf", "%31[0-9]", str);

printf("str=%s/n", str);

输出结果:

1
str=123456

上面的格式中,[0-9]表示这是一个仅包含0-9这几个字符的字符串,前面使用数字31修饰词表示这个字符串缓冲区的最大长度

sprintf():

描述

C 库函数 int sprintf(char *str, const char *format, …) 发送格式化输出到 str 所指向的字符串。

声明

下面是 sprintf() 函数的声明。

1
int sprintf(char *str, const char *format, ...)

实例

下面的实例演示了 sprintf() 函数的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <math.h>

int main()
{
char str[80];

sprintf(str, "Pi 的值 = %f", M_PI);
puts(str);

return(0);
}


指针

1.定义(略)

2.指针的算数意义

  • 指针的每一次递增,它其实会指向下一个元素的存储单元。
  • 指针的每一次递减,它都会指向前一个元素的存储单元。
  • 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。

3.指针数组

用一个指向字符的指针数组来存储一个字符串列表,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

const int MAX = 4;

int main ()
{
const char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
};
int i = 0;

for ( i = 0; i < MAX; i++)
{
printf("Value of names[%d] = %s\n", i, names[i] );
//names[i]前面不需要加*,因为c中字符串指针输出全部只需要开头的指针,
//即数组名str,加了*只会取出第一个元素
}
return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

1
2
3
4
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali

4.指向指针的指针

(二维数组中有所体现)

5.从函数返回指针

static int r[10];//函数里的变量如果想返回地址需要加上static

image-20230201230854265

6.函数指针

函数指针是指向函数的指针变量。

通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。

函数指针可以像一般函数一样,用于调用函数、传递参数。

函数指针变量的声明:

1
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

回调函数

‘’函数指针作为某个函数的参数’‘

函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。

简单讲:回调函数是由别人的函数执行时调用你实现的函数。

以下是来自知乎作者常溪玲的解说:

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。