-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
3748 lines (3615 loc) · 108 KB
/
main.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
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//#include <stdio.h>//包含头文件,相当于将头文件中的内容全部放到这里了。
///*#开头的命令,叫预处理指令。
// 一个应用程序从写代码开始到程序运行,经历的过程:
// 编辑,预处理,编译,汇编,连接,运行
// 1,编辑:写代码
// 2,预处理:#号开头的指令叫预处理指令,主要是做代码替换的功能,
// 因为C语言是先声明再使用的语言。
// 因为我们使用printf函数,就要包含printf所在的头文件。
// 因为stdio.h文件中,有关于printf这个函数原型的声明。
// 3,编译:将代码翻译成汇编语言的过程。
// 4,汇编:生成提供给链接使用的目标代码的过程。
// 5,链接:将多个文件的目标代码链接成应用程序的过程。
// 6,运行,将应用程序加载到内存中运行。
// *
// 关于函数有三个术语:
// 1,函数的原型的声明:声明函数返回值类型 函数的名称,以及参数列表。
// 2,函数定义
// 3,函数调用:函数调用的依据就是函数原型。根据函数原型进行调用
// 编译器会根据函数原型的声明,来测试调用的是否正确。
// * */
//
//int main() {//写任何一个C语言或者C++程序,必须有且只有一个main函数。
// //它是所有应用程序执行的入口。
// //int main()叫函数头,{}大括号包裹的这部分代码
// //我们叫他函数体,函数体中写程序的运行逻辑。
// printf("Hello, World!\n");//函数的调用。
// //关于字符串:双引号引起来的叫字符串,字符串里有两类字符
// //一类叫普通字符,对于printf来讲,原样输出,
// //还有一类叫特殊字符,例如\n表示换行,%开头的表示格式化输出
// // 后面的值。
// printf("今天是个好日子\n");
// printf("我要努力学习,认真听课,争取迎娶白富美\n");
// printf("今天是%-3d号",13);//每条语句后必须加;表示执行完毕。
// return 0;
//}
/*
定义变量四件事:
1,比照类型分配对应大小的空间。例如int就是四个字节。
一个字节8个bits,4个字节就是32个bits.
2, 给这个空间取名,也就是所谓的变量名。它代表里面的值。
3,要赋初始值,如果不赋初始值则为乱值。
4,一定有个首地址,记为&变量名,(例如:&a);
* */
//#include <stdio.h>
//int main(){
// int a = 0;
// int b = 0;
// int sum = 0;
// a = 123;//= 赋值运算符,它就是把右边的值赋值给左边的变量。
// b = 456;//
// sum = a+b;//a代表的值加上b代表的值,赋值给sum
// printf("a = %d , b= %d , sum = %d\n",a,b,sum);
// /*printf功能是输出双引号引起来的字符串,*/
// /*逗号就表示分隔符,我们调用函数的依据是函数原型的声明*/
//}
/*例,输入两个数,计算两个数的和,并且输出*/
//#include <stdio.h>
//int main(){
// int age1 = 50;//十进制表示的常量的写法
// int age2 = 062;//八进制表示的常量的写法
// int age3 = 0x32;//十六进制表示的常量的写法
// printf("%d %d %d\n",age1,age2,age3);
// printf("0%o 0%o 0%o\n",age1,age2,age3);
// printf("0x%x 0x%x 0x%x\n",age1,age2,age3);
//}
/*
如何理解有无符号?
从两个角度理解
(1)从数据类型的角度。理解有无符号。
有符号,就是二进制中的第一位存放符号位,0表示正数,1,表示负数。
无符号,就是二进制中的所有位,都表示数值位,没有符号位。
也就是无符号的数据类型,只能存放正数。
(2) 我们可以选择按有无符号来输出。
如果按有符号输出,第一位如果是1,那么是补码,要推导到原码才知道是什么值。
如果按无符号输出,就没有符号位,就全是数值位,就是8421码。
* */
//#include <stdio.h>
//int main(){
// printf("只要你坚持不懈的努力,一定会100%%de成功率.");
//}
/*
%d 按有符号10进制(读入或者输出)
%u 按无符号10进制(读入或者输出)
%x 按无符号16进制(读入或者输出)
%o 按无符号8 进制(读入或者输出)
* */
/*关于字符串:双引号引起来的叫字符串,字符串里有两类字符
一类叫普通字符,对于printf来讲,原样输出,
还有一类叫特殊字符,例如\n表示换行.
%开头的表示格式化输出后面的值。
%%表示输出一个%*/
/*
、定义变量四件事:
1,比照类型分配对应大小的空间。例如int就是四个字节。
一个字节8个bits,4个字节就是32个bits.
2, 给这个空间取名,也就是所谓的变量名。它代表里面的值。
(扩展来讲,所有的标识符都代表值)
3,要赋初始值,如果不赋初始值则为乱值。
4,一定有个首地址,记为&变量名,(例如:&a);
*/
//#include <stdio.h>
//int main(){
// short int a = -123;
// printf("%ho\n",a);
// printf("%hx\n",a);
// printf("%hu\n",a);
// printf("%hd\n",a);
//}
/*
short int 2 [-32768,32767]
long int 4 (-21亿,21亿)
int 4 (-21亿,21亿)
unsigned short int 2 [0,65535]
unsigned long int 4 [0,42亿)
unsigned int 4 [0,42亿)
float 4 -10^38 10^38
double 8 -10^308 10^308
* */
//#include <stdio.h>
////数值加到最大,会变最小的。
////数值最小减1,会变最大。所以我们学习数据类型时,一定要关注
////数值范围。
///*写一个浮点型常量,有两种写法:小数形式和科学计数法
// 写一个正确的科学计数法表示的浮点数,要满足两条:
// 1,e/E前必须有数字
// 2,e/E后必须有整形数
// */
//int main(){
// char ch = 'a';//把字符常量a赋值给char型变量ch,
// //实际上就是字符对应的ASCII码值赋值给ch了。
// printf("%hhd\n",ch);
// printf("%c\n",ch);
// char ch1 = -3;
// printf("%hhd\n",ch1);
// return 0;
//}
/*
char类型有两种身份:
1,一个字节整型数的数据类型。
char a = -3;
2, 存放字符的ASCII码值(就是给每个字符编的号码);
char ch = 'A';
关于ASCII码,我们需要记住的:
空格 32
'0' 48
'1' 49
'9' 57
'A' 65
'B' 66
'Z' 90
'a' 97
'b' 98
'z' 122
'\n' 10
'\a' 7
'\b' 8
'\t' 9
'\0' 0 c语言系统设计出来一个字符,表示字符串末尾,
大写字母和小写字母相差 32,大写字母小,小写字母大。
0到127,共128个。
* */
/*
例如:输入一个字符,判断它是大写字母,小写字母还是数字字符
* */
//#include <stdio.h>
//int main(){
// /*所有带* 的指针变量,在32位系统下都是4个字节,64位系统下8个字节*/
// int a = 30;
// int * p = &a;//p只能保存的是int型内存块的地址。
// printf("1:%d\n",p[0]);//[i]表示某个地址后,下标为i的内存块,啥样类型的内存块,就看p是啥样内存块的地址,啥样内存块的地址,p[i]就是啥样内存块。
// printf("2:%d\n",(&a)[0]);
// (&a)[0] = 40;
// printf("3:%d\n",p[0]);
// float b = (float)3.14;
// float * q = &b;//q只能保存的是float型内存块的地址。
// printf("4:%.2f\n",q[0]);
// q[0] = (float)5.86;
// printf("5:%.2f\n",b);
// char ch = 'A';
// //&ch的数据类型是char * 型。
// char * r = &ch;
// (&ch)[0] = 'B';
// printf("6:%c\n",r[0]);
// char * w = "w\x53\\\np\103q";//把一个字符串的地址赋值给char *型的指针变量,实际上是字符串第一个字符的地址赋值给指针变量了。
// printf("7:%d\n",w[1]);
//}
/*
关于转义字符:
1,在单引号或者双引号引起来的字符序列中,\将其后面的字符
转义成字符本身,让它失去系统赋予他的特殊含义。
2,在单引号或者双引号引起来的字符序列中,\ooo(至多三个八进制数),表示八进制
数作为ASCII码值,对应的字符。\xhh(最多两个十六进制数),表示16进制数作为ASCII
码值,对应的字符。
*/
//#include <stdio.h>
//int main(){
// int a = 30;
// int *p = &a;
// printf("%d\n",p[0]);//30
// a = 40;
// printf("%d\n",p[0]);//40
// p[0] = 50;
// printf("%d\n",a);//50
// int b = 100;
// p = &b;
// printf("%d\n",p[0]);//100
// p[0] = 200;
// printf("%d\n",a);//50
//}
//#include <string.h>
//#include <stdio.h>
/*
int strlen( char *_Str);
函数原型有三部分构成 返回值类型 + 函数名 + 形参列表,是我们调用函数的依据。
返回值类型:函数运算完后,返回的数值的类型,调用者就可以根据类型,定义相应的变量,来接收函数返回值数值,进行下一步处理。
函数名:为了调用的。当然要符合命名规范。
函数形参:函数原型括号里面的就是形参,函数被调用时,比照类型分配空间,接收实际参数的值的。
形参相当于等号的左侧,实参相当于等号的右侧。
必须按数目一样,类型一样,顺序一样,实参赋值给形参(自动赋值的)。
*/
/*
int scanf( char *__format, ...)
返回值类型是int,我们查资料知道,它是正确读取数值的个数。
* */
//#include <stdio.h>
//int main(){
// printf("%d\n",sizeof(int));//4
// printf("%d\n",sizeof(short int));//2
// printf("%d\n",sizeof("abcd"));//5
// printf("%d\n",sizeof("aaaaa"));//6
// printf("%d\n",sizeof(unsigned short int *));//8
// printf("%d\n",sizeof(unsigned long int * ));//8
//}
//int main(){
// int a = 0;
// int b = 0;
// int k = scanf("%d%d",&a,&b);
// //1,输入xyz ,输出0
// //2,输入3 xyz,输出1
// //3, 输入3 5 输出2
// //4, 输入3 5 7 输出2
// printf("%d",k);
// if(k == 2){
// printf("两个数的和是:%d",a+b);
// }else{
// printf("输入错误!");
// }
//}
/*
例题:有个函数叫pow,它能计算两个数,例如x,y 能计算x的y次方。在#include <math.h>定义的
现在输入两个数x,y,你能写出代码计算x的y次方吗?
* */
//#include <math.h>
//int main(){
// int x = 0;
// int y = 0;
// int k = scanf("%d%d",&x,&y);
// if(k == 2){
// double result = pow(x,y);//函数调用赋值给变量,就是函数的返回值赋值给变量了
// printf("%lf",result);
// }else{
// printf("数据输入错误");
// }
//}
/*例题:
double atof(const char *_String);
有个库函数叫atof,它的函数原型是上面的,形参是给个数值字符串的首地址,
返回值,就是将字符串里面的数值,转换成double型的值了。
请写代码将“123.456789”,转成double型数值,并保留小数点后两位输出。
*/
//请写代码将“123.456789”,转成double型数值,并保留小数点后两位输出。
//double atof(char *_String);
//int main(){
// char * str = "123.456789";
// double result = atof(str);
// printf("%.2lf",result);
//}
//#include <math.h>
/*例题:
double atof(const char *_String);
有个库函数叫sqrt,它的函数原型是上面的,形参是给个数值字符串的首地址,
返回值,就是将字符串里面的数值,转换成double型的值了。
请写代码将“123.456789”,转成double型数值,并保留小数点后两位输出。
*/
/*有个库函数,叫sqrt,函数原型 double sqrt(double _X);
作用是开根号。参数有一个,要被开根号的数值,
返回值是开根号后的结果。
题目:实现如下程序,输入一个数,请输出开根号的结果值,小数点后保留三位。*
*/
//#include <stdio.h>
//#include <string.h>
//int main(){
// double x = 0;
// scanf("%lf",&x);
// double y = sqrt(x);
// printf("%.3lf",y);
//}
//strlen
/*
有个库函数叫strcmp,功能是比较字符串的大小,
逐个字符比较ascii码值,例如 ABcd ab 第二个串大于第一个串,返回-1。
ABcd ABab 第一个串大于第二个串,返回1。
它的函数原型 int strcmp( char *_Str1, char *_Str2);
形参有两个,传入两个字符串首地址。
返回值:第一个串大于第二个串,返回值为1,
第一个串小于第二个串,返回值为-1,
如果字符串相同,返回值为0;
给定两个字符串,编程输出:(1)第一个大于第二个串,
(2)第一个小于第二个串,
(3)相等。
“bacded” "baCDEd"
* */
//给定两个字符串,编程输出:
// (1)第一个大于第二个串,
// (2)第一个小于第二个串,
// (3)相等。
//#include <string.h>
//#include <stdio.h>
//int main(){
// char * str1 = "bacded";
// char * str2 = "baCDEd";
// /*请加入你的代码*/
// int k = strcmp(str1,str2);
// if(k == 1){
// printf("第一个大于第二个串");
// }else if(k == -1){
// printf("第一个小于于第二个串");
// }else{
// printf("相等");
// }
// /*请加入你的代码完毕*/
//}
/*
有个库函数叫strchr,
函数原型是char * strchr( char *_Str,int _Val);
作用:在字符串中查找某个字符出现的位置,
形式参数1,字符串的首地址。
形式参数2,要查找的字符。
返回值:该字符出现在字符串中的地址。
* */
// 请调用该函数,输出地址后的所有字符。
//#include <stdio.h>
//#include<string.h>
//int main(){
// char * str = "abcdefgdijklmnopq";
// char chr = 'd';
// char * res = strchr(str,chr);
// printf("%s",res);
//}
// #include <stdio.h>
// int main(){
// printf("%d\n",sizeof(int));//4
// printf("%d\n",sizeof(short int));//2
// printf("%d\n",sizeof(long int));//4
//
// printf("%d\n",sizeof(unsigned int));//4
// printf("%d\n",sizeof(unsigned short int));//2
// printf("%d\n",sizeof(unsigned long int));//4
//
// printf("%d\n",sizeof(char ));//1
// printf("%d\n",sizeof(unsigned char ));//1
// printf("%d\n",sizeof(unsigned long long int ));//4
//
// printf("%d\n",sizeof(float ));//4
// printf("%d\n",sizeof(double));//1
//
// printf("%d\n",sizeof(unsigned int *));//8
// printf("%d\n",sizeof(unsigned short int *));//8
// printf("%d\n",sizeof(unsigned long int * ));//8
// }
/*
sizeof(字符串)就是字符串字符个数+1。
sizeof(指针变量)就是8个字节。
* */
/*
有两点好处(理解):
1,代码可读性好
2,维护方便
*/
//#define WELCOME "welcome join us!"
//#define PI 3.14
//#include <stdio.h>
//int main(){
// int r = 0;
// printf(WELCOME);
// scanf("%d",&r);
// printf("周长:%lf\n",PI * 2 * r);
// printf("面积:%lf\n",PI * r * r);
//}
//预处理阶段完成的,做代码替换,代码中所有的3都用PI替换
/*用#define的好处
1,代码可读性好
2,维护方便*/
#include <stdio.h>
/*
关于数组:
1,数目固定,类型相同,连续存放一组有序的集合。
2,C语言规定,数组名就是内存块的首地址,它是一个指针常量(数组名不能自增自减,也不能另外赋新值)
3,a[i]表示a代表的地址后,第i个内存块(啥样类型的内存块呢?就看a是啥样类型内存块的地址。
啥样内存块的地址,就啥样类型的内存块)。
4,部分元素赋初始值,其它未赋值的元素均为零,如果不赋初始值,所有值都为乱值。
数值型(int a[10])只有一种赋初始值的方法。
char型数组有两种赋初始值的方法,第一种,按数值型方法来赋值。
char str[100] = {'a','b',-3};
第二种按字符串的方法来赋值:
char str1[100] = {"abcde"};
5,sizeof(数组名),测试的是数组的大小。
6,数组长度如果不写的前提条件是:必须全部元素赋初始值了。
7,数组名作为函数形参,退化成指针变量。
* */
/*
20、输入一串字符,将其中的大写字母变成对应的小写字母并输出。
* */
#include <math.h>
#include <strings.h>
/*任意输入两个double型的数(x和y),编程实现,输出x的y次方的结果。*/
//int main(){
// double x = 0;
// double y = 0;
// double z = 0;
// //预防性编程
// int k = scanf("%lf%lf%lf",&x,&y,&z);
// if(k != 3){
// printf("输入错误");
// return 0;
// }
// if(x<=0||y<=0||z<=0||x+y<=z||x+z<=y||y+z<=x){
// printf("无法构成三角形");
// return 0;
// }
// double s = (x+y+z)/2;
// double area = sqrt(s*(s-x)*(s-y)*(s-z));
// printf("%.2lf",area);
// return 0;
//}
/*
(一)算术运算符:
+ - * / % -(负号)
关于 /:
(1)两个整数相除,必得整数,为地板除。
(2)分子或者分母,只要有一个是浮点数,就是通常意义的除法了。
(3)分母不能为0,否则崩溃。
关于%:
(1)用于计算两个数相除后得到的余数。余数为0,表示两个数整除了。
(2)参与运算的量必须是整形量,其结果也是整形量。
(3)某个正数和n取余,其结果范围是[0,n-1]。
(二)关于自增 自减:
(1)自增自减只能应用于变量。例如数组名就不能自增自减。
(2)单独的一条语句,i++或者++i是没有区别的。
但是i++或者++i在其它表达式上的时候,变量在前,先用变量参与
所在表达式的运算,然后再自增。符号在前,先自增,再参与所在表
达式的运算。(i--和--i规则相同)
(3) 当多个+或者多个-连写的情况,编译器识别前两个+或者前两个-为自增
自减运算符。
(三)关于关系运算符号:> >= < <= == !=
1,关系运算的结果只能是0(假),1(真)
2,只能表达简单的关系。例如某个数,3<x<5,这样写是错误的。
应该用逻辑运算符连接起来 3<x && x< 5
3,= 优先级是14,表示赋值,把右侧的值赋值给左侧的变量。
== 优先级是7 ,表示比较,相等为真,不相等为假。
(四)关于逻辑运算符:&& (11级优先级) || (12级优先级) !(2级优先级)
(1) 运算结果也只能是0或者1.
(2) 注意短路:例如&&,只要前面有一项为假,后面不会再计算。
||,只要前面有一项为真,后面都不再计算。
(五)关于三目运算运算符:?: 优先级13
嵌套是右结合的,计算是左结合的。
(六)关于赋值运算符:= += -= *= /= %=
&= |= ^= <<= >>= (共10个)
等号左侧一定是可以赋值的内存单元(例如变量)
(七)关于逗号运算符:
(1)逗号表达式是多条赋值语句的表达式写法,计算时,将逗号看成分号。
(2)逗号表达式的结果是以最后一个表达式的结果为结果的。
(八) 关于强制类型转换:
(1)指针类型的数据,可以任意强制转换成任意的指针类型,只要你认为合理。
例如,大小端字节序。CPU在处理整形数的时候,
高字节放到低地址,叫大端。
低字节放到低地址,叫小端。
例如 整形数0x12345678
大端:12 34 56 78
小端:78 56 34 12
如何写程序判断CPU是大端还是小端?
(2)如何取出整型数的第二个字节?
int a = 0x12345678;
(char *)&a
(3)相同类型才可以计算,如果类型不同,会自动转成相同类型计算。
例如int 型 + unsigned int 相加,都会自动转换成unsigned int.
(九)位运算符: & 优先级8,位与运算,两个数逐个比特位进行计算,两位都是1,则为1,否则为零。
| 优先级10,位或运算,两个数逐个比特位进行计算, 两位只要有一个为1,则为1,否则为零
^ 优先级9,位异或运算两个数逐个比特位进行计算,相同为0,不同为1;
<< 优先级5,左移,左移动n位就等于原数乘以2的n次方。
>> 优先级5,右移,左移动n位就等于原数除以2的n次方。
~v 优先级2,自反,所有位,0变1,1变0;
应用场景:
(1)用你所知道的最快的算法,判断一个数是否是2的n(n>=0)次方?
(2)用你所知道的最快的算法,计算一个无符号整型数中,到底有多少个1?
(3)将一个无符号的整形数的第七和第八位置1,代码如何写?
(4)将一个无符号的整形数的第七和第八位置0,代码如何写?
(5) 写代码取的第七位和第八位的值?
(6) 写代码将无符号整形数的后四位清零。
(7) 已知当有 short int BitsToWaitFor,某位如果为1,表示等待的位。
uxEventBits 是当前比特位的情况。如何判断所有位都等到了。
(十)sizeof运算符,优先级是2
(十一) [] ,优先级为1,表示某个地址后第几个内存块。
(十二)& 和 * &块找点,* 点找块。
(十三).和-> 结构体专用的。优先级都为1.
所有表达式的运算规则:
从左向右两两运算赋比较优先级,左边优先级高的,先计算左边的,
右边运算符优先级高的,继续向右找,直到找到相对最好的优先级进行
计算。如果优先级相同,看结合性(单目运算是右结合的,双目运算是
左结合的,三目运算嵌套是右结合,计算是左结合的),左结合,先计算
左边的,右结合,继续向右找,直到找到相对最高的优先级进行计算。
重复以上步骤。
遇到&&和||注意短路。
* */
/**已知当有 short int BitsToWaitFor,某位如果为1,表示等待的位。
uxEventBits 是当前比特位的情况。
如何判断所有位都等到了。*/
//int main() {
// unsigned short int a = 0xffff;
// a &= ~0xf;
// printf("%hhx", a);
//}
/*
for循环的应用场景:
1,已知循环次数,循环变量从零开始,小于多少就循环多少次。
2,已知开始值,结束值,和步长循环时,用for循环。
while循环:
循环次数是根据中间运算结果决定的。此时while就比较方便。
* */
/*
关于强制类型转换:
(1)指针类型的数据,可以任意强制转换成任意的指针类型,只要你认为合理。
例如,大小端字节序。CPU在处理整形数的时候,
高字节放到低地址,叫大端。
低字节放到低地址,叫小端。
例如 整形数0x12345678
大端:12 34 56 78
小端:78 56 34 12
如何写程序判断CPU是大端还是小端?
(2)如何取出整型数的第二个字节?
int a = 0x12345678;
(char *)&a
(3)相同类型才可以计算,如果类型不同,会自动转成相同类型计算。
例如int 型 + unsigned int 相加,都会自动转换成unsigned int.
* */
//int main() {
// int a[] = {1,2,3,4,5,6,7,8,9,10,11,12};
// int n = sizeof(a)/sizeof(a[0]);
//// int couples = n/2;
////
//// for(int i = 0;i<couples;i++){
//// int t = a[i];
//// a[i] = a[n-1-i];
//// a[n-1-i] = t;
//// }
//// for(int i = 0;i<n;i++){
//// printf("%d ",a[i]);
//// }
// /*下面用指针法再做一遍。*/
// int * p = a;
// int * q = a + n - 1;
// while(p<q){
// int t = *p;
// *p = *q;
// *q = t;
// p++;
// q--;
// }
// for(p = a;p<a+n;p++){
// printf("%d ",*p);
// }
//}
//int main(){
// 关于sizeof:
// 能测试常量,变量,数组,类型所占或者应占内存空间的大小,单位字节数。
//(1)测试常量字符串就是字符个数加1。
// printf("%d\n",sizeof("i love china"));//13
///*(2) 测试变量就是变量比照类型分配的空间大小。
//*/
// char ch = 'A';
// printf("%d\n",sizeof(ch));//1
///*(3) 测试数组名就是数组所占空间大小。
//*/
// short int a[10]= {1,2,3}; // short int 类型占2个字节
// printf("%d\n",sizeof(a));//20
///*(4) 测试类型就是类型应该占空间大小。
//*/
// printf("%d\n",sizeof(long long int));//8
///*(5) 测试指针变量,在32位系统下,4个字节,64位系统下,是8个字节。
//*/
// short int a = 10;
// short int * p = &a;
// printf("%d\n",sizeof(p));//8
///*(6) 数组名,作为函数形参,退化成指针变量,sizeof(指针变量),
// * 在32位系统下,4个字节,64位系统下,是8个字节。
//*/
//}
// 关于strlen:
// unsigned long long int strlen( char * str);
// 作用:能测试出从某个地址开始,截止到第一个\0中间字符的个数,(不含\0);
// 参数:接收字符串地址的指针变量。即从此地址开始测试字符串长度。
// 返回值;从某个地址开始,截止到第一个\0中间字符的个数,(不含\0);
//
//int main(){
// char * p = "asfasdf";
// unsigned long long n = strlen(p); // 传入字符串首地址p
// printf("%d\n",n);
// printf("%d\n", strlen("abc")); // 字符串作为参数,C语言中字符串即为字符数组,传入字符数组的首地址,即第一个字符a的地址。
// printf("%d\n", strlen('a')); // 'a'作为字符常量,数据类型与参数char * str不符, 报错。
//}
//13、从键盘输入n和a的值,计算a+aa+aaa+...+aa...a(n个a)的值。
//int main() {
// int n = 10;
// int a = 2;
// int sum = 0;
// for (int i = 0; i < 10; i++) {
// sum = sum * 10 + a;
// printf("%d\n",sum);
// }
// printf("%d",sum);
//}
//*/
//int main(){
// int a = 0;
// int b = (a=3*5, a*10, a+8);
// printf("%d",b);
//}
//int main(){
// char ch = -3;
// short int a = ch;
//}
//14、输入5个数,求它们中最大值和平均值并输出。
//int main(){
// char str[100] = {0};
// scanf("%s",str);
// int i = 0;
// int j = 0;
// for(i = 0;str[i]!='\0';i++){
// if(str[i]!='a'){
// str[j++] = str[i];
// }
// }
// str[j] = '\0';
// printf("%s",str);
//}
//8、编写程序,将用户输入的字符串中所有的字符a用*代替,然后输出。
/*关于函数定义:
1,C语言是先声明再使用的语言,如果调用在前,定义在后,必须进行函数原型的声明。
函数原型的声明就是告诉编译器,有这么样的函数,编译器会根据函数原型的声明
来测试函数调用的语法是否正确。如果定义在前,调用在后,可以不进行函数原型的
声明。
2,函数返回值值类型是函数运算完成后,返回的数值的类型,调用者就可以根据返回值类型,定义相应类型的变量
来接收函数返回值,进行下一步的处理。函数的形参是函数被调用时,根据它的类型分配空间,接收实际参数的值的。
可以认为形参就是函数的局部变量。定义在函数体中的变量叫局部变量,局部变量保存函数运算过程中中间结果数据的。
局部变量的作用范围是本函数(不同的函数,可以用相同名字的局部变量,他们不冲突,代表不同的存储单元)。
3,函数被调用时,产生栈帧,形参将分配空间,接收实际参数的值。在运行过程中,局部变量也将分配空间。
函数调用结束后,栈帧将释放(形参和局部变量分配的空间会自动释放)(不能返回局部变量的地址)
4, 必须按数目一样,类型一样,顺序一样的原则进行函数实参和形参的结合。实参赋值给形参是单向传递的。
也就是实参的值可以赋值给形参,而形参的改变不会影响到实际参数。
*/
/*输入n的值,计算并输出1*1+2*2+3*3+4*4+5*5+...+n*n的值。要求编写函数f求平方*/
/*42、输入一个不多于19位的正整数,判断它是几位数,
* 并逆序返回各位数字,
* 要求写一个函数,完成这些功能。*/
/*从键盘输入10个数,统计非正数的个数,并计算非正数的和。*/
/*一个皮球从100米高度自由落下,每次落地后反弹回原高度的一半,再落下,再反弹。
* 求当它第10次落地时,共经过了多少米,第10次反弹多高?*/
/*24、输入一个正整数,输出它的阶乘。*/
/*指针是一把双刃剑,带来便利的同时,也带来了不希望改变主调函数的变量的情况下,
* 改变调用者变量的风险*/
//double fun(unsigned int a){//形参设计指针变量,大概率是调用者想得到一些数据,
// double ret = 1;
// for(int i = 1;i<=a;i++){
// ret *= i;
// }
// return ret;
//}
//int main(){
// for(int i = 1;i<=100;i++){
// printf("%.0lf\n",fun(i));
// }
//}
/*
进程和线程:
(1)运行起来的程序叫进程,它是资源管理的最小单位,资源主要指的是内存。
每个进程都有自己独立的内存空间。当然这个空间是虚拟内存,不是物理内存。
(2)同一个进程中多条同时运行的执行路径,线程必须依赖于进程存在。也就是
一个进程中必有一个线程,当然也可以有多个线程。
线程就是CPU调度的最小单位。
内存的五大分区:
(1)栈区 函数的形参和局部变量分配到栈区,函数调用时,形参和局部变量将分配空间,
函数调用结束后,形参和局部变量分配的空间将自动释放。
栈区的大小一般是1M或者2M。
栈的增长方向是向下增长的。
(2)堆区 由malloc函数分配出来的内存空间,分配到堆区,
分配出来的内存必须通过free函数释放内存,否则内存泄漏。
void * malloc(unsigned long long int _Size);
作用:在堆区分配_Size大小的内存空间,单位字节。
参数_Size:表示将在堆上分配多少字节的内存空间。
返回值 void * :返回产生_Size字节数内存空间的首地址。
使用时强制类型转换到实际的指针类型。
(3)常量文本区
常量字符串存放在常量文本区,常量区的内容是只能读的 不能被修改的,修改会崩溃.
(4)全局静态区
全局变量和静态局部变量存放的区域:
函数外定义的变量叫全局变量。
局部变量前static,表示静态局部变量:静态局部变量存放到全局静态区,
每次函数调用结束后,内存不释放,值仍保留。每次函数重新调用时,也不会为其
重新分配内存,只初始化一次。
在编译链接阶段。
未初始化的全局变量和静态局部变量 分配到BSS段。
也将置为0.
初始化的全局变量和静态局部变量,分配到DATA段。
(5)程序代码区
程序的代码存放的区域。
* */
//#include <stdlib.h>
//
//char *fun() {
// //char str[100] = {"hello world!"};//栈内存,函数调用完后立即释放,导致指针成为野指针
// char *p = (char *) malloc(100);//产生堆内存,因为函数调用完后,不释放。
// char *str = "hello word!";
// int i = 0;
// for (i = 0; str[i] != '\0'; i++) {
// p[i] = str[i];
// }
// p[i] = '\0';
// return p;
//}
//int main(){
// char * p = fun();
// printf("%s",p);
// free(p);//必须要释放,否则内存泄漏。
// p = NULL;//free后,p的值不可能被改变。因为我们要想改变主调函数变量的值,必须传入
// //变量的地址才有可能。此处free时,没有传入变量地址,所以变量的值不可能被free改变。
//}
//#include <stdlib.h>
//char * fun(){
// char * p = (char *)malloc(100);//产生堆内存,因为函数调用完后,不释放;
// char * str = "hello world!";//若没有上一行代码malloc函数,此处的str将会变成野指针,因为函数被调用完成后,局部变量在栈内的内存会被自动释放;
// int i = 0;
// for(i = 0;str[i] != '\0';i++){
// p[i] = str[i];
// }
// p[i] = '\0';
// return p;
//}
//int main(){
// char * p = fun();
// printf("%s\n",p);
// printf("%x\n",p);
// free(p);//必须要释放,否则会内存泄漏;
// /*free后,p的值不可能被改变。因为我们要想改变主调函数变量的值,必须传入变量的地址才有可能。
// * 此处free时,没有传入变量地址,所以变量的值不可能被free改变*/
// printf("%x\n",p);
// printf("%s\n",p);
// p = NULL;
// printf("%x\n",p);
// printf("%s\n",p);
//}
//void fun(char * * q){
// *q = "hello world";//这里的*q,就是找到了主调函数的p.
//}
//int main(){
// char * p = "abcdef";
// fun(&p);
// printf("%s",p);
//}
//char * fun1(){
// char ch = '3';
// return &ch;//不能返回局部变量的地址。
//}
//char fun2(){
// char ch = '3';
// return ch;
//}
//int main(){
// char *p = fun1();
// printf("%d\n",*p);
// char ch = fun2();
// printf("%d\n",ch);
//}
// void fun(int a){
// int b = 0;
// static int c = 0;
// b++;
// c++;
// printf("%d: b=%d,c=%d\n",a,b,c);
// }
// int main(){
// for(int i = 0;i<2;i++){
// fun(i);
// }
// }
/*
/*
1,指针:
指针也叫地址,内存块的首位置,英文名叫pointer,
它是一个常量,例如 int a= 10;&a就是a的地址,就是一个常量值。
再例如数组名,int a[10],a就是常量,a就是地址,也叫指针。
2,指针变量:
顾名思义,指针(地址)变量,也就是存放指针(地址)的变量。
例如int * p :p只能存放int型内存块的地址。
关于指针变量,要注意:
(1)指针变量必须初始化,否则禁止使用。
(2)把谁的地址赋值给指针变量,换句话说,指针变量保存了谁的
地址,我们就说,指针变量指向了谁。
(3)在32位系统下,所有指针变量都是4个字节。
在64位系统下, 所有指针变量都是8个字节。
3,*p的含义:
点找块(根据p代表的地址值,找对应类型的内存块。
啥样类型?就看p代表啥样类型内存块的地址,
啥样类型内存块的地址,就找啥样类型的内存块。)
注意:(1)如果p为NULL,*p 会崩溃。
(2)如果p为乱值, *p 会崩溃。
4,p+n的含义:
表示p代表的地址,向右偏移n个存储单元,得到一个新的地址值。
啥样存储单元?就看p代表啥样类型存储单元的地址,
啥样类型存储单元的地址,就偏移n个存储单元的字节数。
例如:double * p ; p+=3;//p向右跳了24个字节。
在一个连续空间中,两个指针相减,等于间隔的内存单元的个数。
(啥样内存单元?就看两个指针是啥样类型存储单元的地址,
啥样类型存储单元的地址,就间隔啥样类型的存储单元。)
5,p[n]的含义:
表示p代表的地址后,下标为n的内存块。
(啥样类型的内存块?就看p代表啥样类型内存块的地址,
啥样类型内存块的地址,就为啥样类型的内存块)。
6,支持的运算:
(1),算术运算符 + - * / % -(负号)
4 4 3 3 3 2
两个指针能相加吗?不能。
一个指针能加个整型数吗?能,表示向右偏移n个存储单元,得到一个新的地址。
两个指针能相减吗?在一个连续空间中,两个指针相减才有意义。
两个指针 * / % - 都是没有意义的。
(2)(强转),指针数据可以强转成任意的指针类型。
整形数据是否可以强转成指针数据呢?可以,可以互相转。
(3) 自增,自减(++ --),优先级为2
指针变量能否自增,自减?能。
(4) 关系运算符 > >= < <= == !=
6 6 6 6 7 7
指针数据是支持的。
(5) 逻辑运算符 && || !
11 12 2
非常支持。
(6) 三目运算符 ?: 支持。
(7) 赋值运算符 相当的支持。
(8) 逗号运算符 支持。
(9) 位运算符 & | ^ << >> ~ 指针不支持
8 10 9 5 5 2
(10) sizeof运算符: sizeof(指针变量) 32系统下都是4个字节。
32系统下都是8个字节。
(11) [] 优先级是1级运算符。支持
表示某个地址后,下标为n的内存块。
(12) &和* 支持。
指针变量的地址,是**的类型。
普通变量的地址,是*的类型。
* 就是点找块。
(13) .和-> 都是一级运算符,结构体使用。
* */
// 11月30日作业
//27、输入一串字符,逆序输出。要求使用数组实现。
//void func(char *str) {
// int n = strlen(str);
// int temp = 0;
// for (int i = 0; i < n / 2; i++) {
// temp = str[i];
// str[i] = str[n - i - 1];
// str[n - i - 1] = temp;
// }
//}
//
//int main() {
// char str[100] = {0};
// printf("请输入一个字符串: ");
// scanf("%s", str);
// func(str);
// printf("逆序输出字符串: %s", str);
//}
//28、求1-1/2+1/3-1/4+...+1/99-1/100的值。
//void func(float *p_sum) {
// *p_sum = 0;
// int symbol = 1;
// for (int i = 1; i <= 100; i++) {
// *p_sum += symbol * (1.0 / i);
// symbol = -symbol;
// }
//}
//
//int main() {
// float sum = 0;
// func(&sum);
// printf("%.2f", sum);
//}
//30、求两个正整数的最大公约数。
#include <stdio.h>
#include <assert.h>
/*辗转相除法,又称欧几里得算法,用于计算两个正整数a和b的最大公约数(GCD)。
* 其计算过程基于这样一个事实:两个数的最大公约数不改变,如果较大数减去较小数。
* 更有效的方法是用较小数除较大数,取余数,再用较小数除得到的余数,依此类推,
* 直至余数为0。此时,较小数即为两数的最大公约数。*/
// 定义一个函数来计算两个整数的最大公约数
//int gcd(int a, int b) {
// // 当b不等于0时,继续执行循环
// while (b != 0) {
// // 计算a除以b的余数,并将其存储在r中
// int r = a % b;
// // 将b的值赋给a
// a = b;
// // 将余数r的值赋给b
// // 下一轮循环将使用新的a和b值继续计算
// b = r;
// }
// // 当b等于0时,循环结束,此时a中存储的就是最大公约数
// // 返回最大公约数a
// return a;
//}
//
//int main() {
// int a = 48, b = 18;
// printf("GCD of %d and %d is %d\n", a, b, gcd(a, b));
// return 0;
//}
//31、求100之内自然数中奇数之和。
//int func(int n) {
// int sum = 0;
// for (int i = 0; i < n; i++) {
// if (i % 2 != 0) {
// sum += i;
// }
// }
// return sum;
//}
//
//int main() {
// int n = 0;
// scanf("%d", &n);
// int sum = func(n);
// printf("%d", sum);
//}
//32、输出所有200-400之间能被3整除且个位数字为7的整数。
//int fun(int a[]){ //数组名作为函数参数,将退化成int *a
// int cnt = 0;
// for(int i = 200;i<=400;i++){
// if(i%3 == 0&& i%10 == 7){
// a[cnt] = i;
// cnt++;
// }
// }
// return cnt;
//}
//int main(){
// int arr[200] = {0};
// int cnt = fun(arr);
// for(int i = 0;i<cnt ;i++){
// printf("%d ",arr[i]);
// }
//}
//33、编程计算1*2*3+4*5*6+...+97*98*99
//long long int func() {
// long long int sum = 0;
// for (int i = 1; i <= 97; i = i + 3) {
// sum += i * (i + 1) * (i + 2);
// }
// return sum;
//}
//
//int main() {
// long long int res = func();
// printf("%lld", res);
//
//}
//41、从键盘输入一个字符串,再输入两个正整数m和n,输出字符串中从m开始,连续n个字符。例如,输入abcdefg,2,3,输出bcd。
//void func(char *p_str, int m, int n) {
// for (int i = 0; i < n; i++) {
// printf("%c", p_str[m-1]);