Manco的学习日志之C语言篇
关系运算
关系运算中最终的只会输出1(true)和0(false)两个结果,可以根据这个特性来做一些判断。
关系运算中比较运算符的优先级低于运算运算符,但是赋值运算符的优先级又低于比较运算符。
IF判断语句
If判断语句中,括号内为循环开始的判断条件,大括号内为if循环开始后进行的操作,if循环可以进行多层的嵌套。
同时,if判断语句的大括号后面可以接else+大括号表示否则的意思,用来运行当不满足if语句条件时的相应语句。以下为示例程序:
1. #include <stdio.h>
2. int main()
3. {
4. int a = 0, b = 0, c = 0;
5. printf("您需要支付的金额为:");
6. scanf("%d",&a);
7. printf("您实际支付的金额为:");
8. scanf("%d",&b);
9. if(b >= a){
10. c = b - a;
11. printf("找您%d元",c);
12. }
13. else{
14. printf("您的金额不足以购买商品!");
15. }
16. }
While循环语句
在While循环语句中,小括号内的代码是While语句执行的条件,当满足条件时While大括号内的代码执行,每执行一次均会再次在小括号内进行一次判断,直至最后的结果不符合小括号内的条件,最终跳出循环。
Do-While循环语句
Do-While循环语句可以说是While循环语句的升级版,Do-While循环语句中无论循环条件是否满足,均会强制运行一次大括号内的语句。
以下为示例程序:
17. #include <stdio.h>
18. int main()
19. {
20. int x = 0, n = 0;
21. printf("请输入需要判断的数字:");
22. scanf("%d",&x);
23. if(x<0)
24. x=-x;
25. do
26. {
27. n++;
28. x/=10;
29. }
30. while(x >0 );
31. printf("您输入的数字的位数为:%d\n",n);
32. return 0;
33. }
For循环语句
For循环语句中,小括号中的三个语句分别表示为设定循环开始时的初始值,循环开始的条件,每次循环结束后作出的动作,
所以For循环语句更适合做一些类似阶乘的计算或思路。
以下为示例代码:
34. #include <stdio.h>
35. int main()
36. {
37. int x = 0, n = 0;
38. printf("请输入需要判断的数字:");
39. scanf("%d",&x);
40. if(x<0)
41. x=-x;
42. do
43. {
44. n++;
45. x/=10;
46. }
47. while(x >0 );
48. printf("您输入的数字的位数为:%d\n",n);
49. return 0;
50. }
逻辑运算&条件运算
逻辑运算指的就是与 或 非 这三种不同的关系分别使用
非 ! ; 与 &&; 或 ||;
且优先级! > && > ||
以下为各种不同运算符的优先级。
级联和多级嵌套
此内容仅仅为了强调在进行级联或者多级嵌套时,需要注意是用大括号保证else的进行,即代码习惯问题。
Switch-Case多路分支语句
1. #include<stdio.h>
2. int main ()
3. {
4. int a;
5. scanf("%d",&a);
6. switch(a){
7. case 1:
8. printf("Hello! This is 1");
9. break;
10. case 2:
11. printf("Hello! This is 2");
12. break;
13. case 3:
14. printf("Hello! This is 3");
15. break;
16. default:
17. printf("Hello! You should write 1 or 2 or 3!");
18. break;
19. }
20. return 0;
21. }
在Switch-Case语句中,可以设置多种不同情境下的返回值或者不同的运行代码,需要注意的是每个case后需要加上break来表示这一个分支已经结束,避免进行后续的判断。
函数的定义与使用
函数的结构其实很简单,结构大致如下
1. int sum(int begin, int end){
2. int i = 0;
3. int sum = 0;
4. for(i = begin; i <= end; i++){
5. sum += i;
6. }
7. printf("%d到%d的和是%d.\n",begin,end,sum);
8. return sum;
9. }
圆括号内是函数的参数,大括号内的所有代码可以当做运算关系。值得注意的是最开头的函数类型,int表示此函数需要有一个返回值可以输出一个我们需要的值供以后使用,函数中需要用(return 表达式)来表示一个返回值,而void则表示不输出返回值,这也就意味着不需要使用上面的代码来做一个返回值的输出。
学习联想:我们之前写的所有的函数中开头的int main()也是一个函数,只不过这个main函数是函数库自带的一个函数,而这里我们学习的是怎么自定义一个自己需要的函数。
函数原型
在C语言自定义函数时,你可以吧函数头放在开头作为一个声明,而函数的具体定义放在后面来作为使用时的参考。
代码参考如下
1. #include<stdio.h>
2. int sum(int begin, int end); //声明
3. int main()
4. {
5. sum(10,20);
6. sum(30,40);
7. sum(35,45);
8. return 0;
9. }
10. int sum(int begin, int end) //定义
11. {
12. int i = 0;
13. int sum = 0;
14. for(i = begin; i <= end; i++){
15. sum += i;
16. }
17. printf("%d到%d的和是%d.\n",begin,end,sum);
18. return 0;
19. }
所谓的函数头即第2行的声明代码,而真正的函数的定义则是第10行开始。
函数的传值
在自定义函数中,我们无法编译出一个用于传值的函数,即将两个变量 a b 的值利用一个函数直接相互将值进行调换。即
1. int exchange(int a, int b){
2. int t;
3. t = a;
4. a = b;
5. b = t;
6. }
此函数无法实现所设想的转换。
本地变量
通过对本地变量的学习,我们知道了前面传值函数无法成立的原因,即在一个大括号内定义的所有变量,产生的所有值,均不会被带出到上一级大括号内,且在此括号内可以定义与上一级括号内相同名称的变量,同时在这一级大括号内此变量会覆盖其上一级的同名变量,同时这个变量的所有运算结果均不会被带出到上一级变量。而且在这一级的大括号中我们可以使用上一级变量中的所有变量,但是在这一级中运算产生的所有结果都不会被带到上一级。
即不同的大括号之间是几乎完全隔离开来的,对于包含关系的大括号,内层大括号虽然也能使用外层大括号的所有变量,但是所产生的一切结果都不会被带出括号。
函数庶事
- 假设我们确定一个函数不需要参数那么我们最好在参数内输入void声明这个函数确实是不需要参数
- 当我们在参数中需要使用逗号运算符时,我们可以多加一层括号表示这个逗号是一个运算符而非标点符号。
- 在C语言中,不支持函数的嵌套定义,但是支持函数的嵌套声明(虽然这并没有什么卵用)
- 在声明一个函数时我们最好单独一行来声明,而非和其他变量一起声明,用逗号分开。
- 在我们使用return来输出返回值时,最好是不要带括号,这样可能会让人误解为这个return()为一个函数声明。
- rturn 0 在特定的情况下是有用的,所以没事不要乱改这行代码。
数组运算
当我们不知道我们输入的数据的数量时,我们可以不在数组的方括号内填入数组的大小,而是直接空着让程序自己来帮我们数。
如果我们知道我们输入的数据的数量,但是我们要对这个数组做一个初始化时,我们可以输入类似 number[n]{0} 来表示这个数组的所有元素均为0,方便后面的赋值操作。
值得注意的是,这个代码代表的仅仅是我们在这个数组输入的第一个元素为0,后面的空缺的数据均为程序自己帮我添上了0,也就是说number[n]{2} 代表的是一个大小为n,第一个数据为2,后面的所有数据均为1的数组。
仅仅在C99中,我们可以设定一个数组特定位置上的数据是多少用number[n]{[x]=n,} 来表示,这种写法可以用来设定一个零元素很多,且数组的大小很大的时候,再次强调,这种写法仅仅适用于C99的环境。
当我们想要去判断一个数组的大小时,我们可以通过表达式 sizeof(a)/sizeof(a[0]); 来表示,这个代码中sizeof是一个判断数据字节大小的工具,sizeoo(a)表明这个a数组的字节大小,sizeof(a[0])表示这个数组中第一个元素的大小,两者相除,即可得到我们想要的数组的大小,且在以后我们改变数组的数据的时候也不需要改动其他代码,即可知道这个数组的大小。
如果我们想要把一个数组里面的所有变量赋给另一个数组,我们不能直接地int b[] = a;必须使用一个循环,分别将数组中的各个数据分别赋值给那个数组中对应的位置。
指针
在前面我们定义的每一个变量都在内存中有一个地址,而指针存在的意义,就是将这个变量的地址给表示出来,而后我们可以对这个地址上所表示的值进行运算。
对于一个指针,我们用*p来表示,代表这是一个指针变量,p代表他的名字,我们可以对这个指针进行和对变量相同的运算。
需要注意的是,如果我们int p,q; 和int p,q;其实是一个意思,都表达为int一个指针p和一个整型变量q。
字符串
字符是我们日常生活中所使用的字面量,实际值需要参照ASCII表进行参阅。在C语言中,若干个字符所组成的一个集合叫做字符集合,叫做字符数组,它无法参加字符串的相关运算,字符串则是在字符数组的末位加上一个’\0’或者0,例如:
1. char hello0[] = {'h','e','l','l','o'};
这代表的是一个字符数组,而下面
2. char hello1[] = {'h','e','l','l','o','\0'};
代表的则是一个字符串,两者之间的区别在于末位的’\0’
如果我们以char一个指针的形式去创建一个字符串,例如:
3. char *word = "hello";
此时我们char的并不是一个数组,而是一个单纯的指针,这个指针指向了一个只读的单词hello,也就是说这个word的类型是一个const char,无法被改变的。
如果我们需要一个可修改的字符串,那么必须是char一个数组而非指针。例如:
4. char word[] = "hello";
当我们需要去读入字符时,我们需要注意的是,字符串的输入是以空格 tab enter来结束的,所以一般而言一个scanf读入的仅仅是一个单词,而且当我们读入单词的时候,我们不知道这个单词的长度是否会超出数组的承载上限,此时我们可以使用%ns(其中n代表最大读入字符量)来限制读入字符的数量,防止因为字符数量读入过多而导致程序的崩溃。
还有一点就是当我们连续读入多个字符串且同时限制的每个字符串读入字符的数量时,当我们前面的字符输入超出前者的字符限制后,会自动将后续的字符放入到后面的字符串中。
注意:当我们定义一个指针(我们认为是字符串)时,需要给这个字符串进行初始化,否则此举可能会导致程序的崩溃!!
例如
5. char *word;
6. scanf("%s",word);
此举可能会导致程序的崩溃,所以切记定义一个字符串时不要用定义指针的方式去定义,而是必须用char word[]的方式去定义我们想要的字符串数组,然后再进行写入的操作。
字符串函数
当我们需要使用字符串运算相关的函数时,我们可以在引用头文件string.h。
Strlen(a)
这个函数的作用是输出字符串a所包含的字符个数,而不包含末位的’\0’
Strcmp(a,b)
此函数的作用是比较a,b两个字符串的大小,函数会将字符串a和字符串b中的各个字符依次相互比较,将最后的值的和加起来,最终得到两者的差(指ASCII表中的差值)
Strcpy(a,b)
此函数的作用是将字符串a中的各个字符一一覆盖到字符串b中,会覆盖b字符串中各个字符的值。
Strcat(a,b)
此函数的作用是将a字符串中的字符直接连接到b字符串的最后一个字符的后面,起连接作用。
———————————————————————————————————————
以上函数的作用很好,但是有一个很致命的缺点,那就是如果字符串的长度过短,而需要放入的字符又太多,这样的话程序就很容易出现问题,由此,我们可以使用一些更为安全的一些函数来进行和上面相同的一些操作。
Strncmp(a,b,n)
此函数的作用并非是说为了安全,而是可以控制比较的位数来实现一些特定的操作。
Strncpy(a,b,n)
此函数的作用依旧是copy,但是我们可以通过后面的n来限制拷贝多少个字符到b字符串中。
Strncat(a,b,n)
同理,此函数的作用还是连接,我们也可以通过n来控制我们向字符串b连上多少个字符。