C语言学习记录——삼 初识C语言(3)

函数

看一个程序:

#include <stdio.h>

Add(int x, int y)

{

int z = x + y;

return z;

}

int main()

{

int num1 = 10;

int num2 = 20;

int sum = 0;

int a = 100;

int b = 200;

sum = Add(num1 , num2);

sum = Add(a , b);

printf("sum = %d ", sum);

return 0;

}

基于之前的一个加法函数做了增添。之前只用了num1, num2,如果想要再算a,b按照之前的思路,还需要再写代码来一步步算。现在我们可以定义一个加法函数,在程序里使用这个加法函数,就可以了。在main之前,我们定义了函数,大括号里的是函数体,小括号里的是函数的参数,int是它的类型。整个过程是,进入main代码块里,引用了add函数,上面的int x,int y 就分别变为num1, num2.经过相加后,add函数返回z,z里面存放了和的值,然后回来,再一次调用,计算a + b,之后打印sum值。这就是定义一个函数。C语言中有库函数和自定义函数,刚才的add就是自定义函数。

数组

数组是一组相同类型元素的集合。列代码:

#include <stdio.h>

int main() {

int arr[10] = {.......}

return 0;

}

我们也可以float,char等类型的数组,只要数组中的元素是同类型,上面的省略号可以自由添加想储存在数组里的数据。接下里具体说说。

int arr [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

当要访问这个数组时,比如要拿出7这个数字用,此时需要注意下标问题,数组是从0开始数的,也就是说现在这个数组里,1的下标是0,2的下标是1,10的下标是9.那么访问这个数组时:

printf(“%d ", arr[5]);这时打印出的是6.访问数组的方式是用下标访问。现在要打印数组里所有的数字,也就是说0-9全都要打印出来,这里就可以用循环体。

#include <stdio.h>

int main() {

int arr [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int i = 0;

while (i < 10)

{

printf("%d ", arr[i]);

i++;

}

return 0;

}

这样就能打印出所有了。

操作符

算术操作符

+ - * / %

加减乘除模。模运算是取余数的算术法,叫做取模。int a = 7%3 得出来的数值是1。这里只是简单介绍,以后也有更详细说明。

移位操作符

>> , <<。分为右移和左移。这个移是移了二进制的位。int a = 1,那么a的表达就为30个0后01,如果a << 1,a左移1位,也就是把这个二进制数字左移一位,那么结果就是30个0后10.最左的0去掉,最右边补零,补完之后,int b = a << 1 然后打印b,就会结果是十进制数字2。不过这时候打印a,还是1,因为a移后的值给了b,所以a不动,如果赋值给a,a就会变。

位操作符

& ^ |

这个位仍然是二进制的位,C语言的基础就是二进制。

& 按位与

| 按位或

^ 按位异或

int main()

{

int a = 3;

int b = 5;

int c = a&b;

a 011

b 101

001

&的规则是只要有一个为假,则为假。C语言中0为假,非零为真。与就是并且,所以一个不符合规则则全部不符合。这样的结果就是001.

^的规则是有一个为真即为真。或就是有一个符合条件就行。则结果为111.

|的规则是对应的二进制位相同为0,不同为1.结果就是110.

赋值操作符

= += -= *= /= &= ^= |= >>= <<=

单目操作符

! 逻辑操作符

- 负值

+ 正值

& 取地址

sizeof 操作数的类型长度

~ 对一个数的二进制位取反

-- 前置、后置---

++ 前置、后置++

* 间接访问操作符(解引用操作符)

(类型) 强制类型转换

对应的双目操作符,三目操作符

!

int a = 10;

int b = 20;

a + b,这个+就是双目操作符,就是两个操作数,所以三目操作符就明白了。继续单目操作符。

int a = 10;

printf(“%d ", a);

printf ("%d ", !a);

打印出结果为10和0。!的作用就看看出来了。0为假,非零为真。如果a = 0,那么结果就是0和1.变为真后默认为为1.

sizeof

sizeof,会计算变量/类型所占空间的大小,单位为4字节。

int main ()

{

int a = 3;

pritnf("%d ", sizeiof(a));

return 0;

}

此时会计算a所占字节大小,是4。

sizeof(int)

sizeof a

sizeof int

前两个都是4,第三个出错。sizeof也可以算数组大小。

int arr[10] = {0};

sizeof(arr)

结果是10 * sizeof(int) = 40,每个数字都是int类型,总共十个。总结一下。数组数字个数 = 数组总大小 / 每个元素大小。

int sz = 0;

sz = sizeof(arr) / sizeof(arr[0] )

~

按位取反,就是把二进制位取反。

int a = 0;

int b = ~a;

printf("%d ", b);

~按二进制位取反。具体来看:

a:0000000000000000

按位取反后,就是1111111111111111,数字个数并不是32位,只是要表达这种转换。但是如果打印,结果就不是1111111111111111对应的二进制数字。这里涉及到原码,反码,补码。二进制数字最左边的数字代表正负,1为负,0为正。负数在内存中存储的时候,存储的是二进制的代码。所以此时这个111111111111111是补码。而要打印出来,打印的是原码,所以减一,在取反,就得到1000000000001,这样输出的结果就是-1。

--,++

int main()

{

int a = 10;

int b = a++;

printf("a = %d, b = %d ", a, b);

return 0;

}

++在a的后面,是后置,后置的用法是a先赋值给b后,再++;先使用再加。前置++是++a,先加再赋值。这是前置和后置的区别,--也同样。关于强制类型转换符:

int a = 3.14这样打印a必定出错,但是如果(int)3.14,强制转换成整数类型,int a = (int) 3.14这样就没有问题了。

至于*符,之后再说。

关系操作符

>

>=

<

<=

!= 用于测试不等于

== 用于测试等于

逻辑操作符

&& 逻辑与

|| 逻辑或

C语言中0为假,一切非零即为真。

int a = 3;

int b = 5;

int c = a && b;

只有两个都为真,c才会真,输出结果为1.而||则是有一个为真则为真。

条件操作符

expr1? expr2:expr3

选择一个表达式,表达式一的结果如果为真,那执行表达式二,表达式二的结果是整个表达式的结果,如果表达式一的结果为假,那表达式三要被执行,表达式三的结果是整个表达式的结果

int a = 10;

int b = 20;

int max = 0;

max = (a > b ? a : b)

具体例子

if ( a > b)

max = a;

else

max = b;

这也是三目操作符。三个操作数。

逗号表达式

表达式之间要用逗号隔开,逗号与下一个表达式之间也要有空格。下标引用、函数调用和结构成员:() [] . ->

int arr[10] = {0};

arr[4]; 这个就是下标操作符。

在之前的加法程序中,调用Add函数时用括号来用函数,这是调用操作符

至于. 和 ->操作符之后再说, 之前的*和&也会再记录。

常见关键字

auto,break,case,char,const,continue, default, do, double,else,enum,extern,float,for,goto,if,int,long,register,return,short,signed,sizeof,static,struct,switch,typedf,union,unsigned,void,volatile,while

一个个写。

auto:当我们写局部变量时,出了范围就不能再用,进入范围就可以用,是自动的属性。局部变量都是自动变量,在声明之前都隐藏了一个auto,auto int a。

break、case:在循环中break可以跳出循环,在switch case语句中也有使用break,可自行搜索。

const:常变量

default:是switch case语句的,意为默认。

do:do while循环

enum、extern:枚举常量,引入外部符号,之前写过。

register:运用一段话

你买电脑的时候说哎呀,我们这个电脑500个g的硬盘,对吧?这叫硬盘数据可以存到硬盘上,也可以存哪里呢?可以存到内存里边儿去,也可以存哪里呢?哎,还有一些比如说寄存器啊,大家可能听过,对吧?寄存器,对吧?啊,这样的东西还有什么呢?还有一些空间呢我们叫什么呢?叫高速缓存。在内存和寄存器之间呢我们还有一种叫高速缓存。高速缓存,那其实数据能够放到这些地方心里我们大概要有个谱啊,要有个谱,这些呢为什么会有这样一个东西呢?大家注意啊,为什么会有这样一个东西呢?啊,其实这个东西呢是这么一个情况啊,诶,我给大家来画一下金字塔的这样一个效果啊,大家注意在我们的计算机里边儿大家可以看到我们的硬盘啊,我们买电脑的时候动不动就500个g的硬盘,对吧?

动不动就500个g的硬盘,但内存呢?你在买电脑的时候有没有说内存500个g啊。很少会去到,我们一般是八个g内存,对吧?八个g内存或者是四个g内存,对吧?如果条件好一点的话,买的电脑的可能是16个g的内存,对不对啊,大概是这么一个情况,对于这是内存啊,内存你会发现内存空间的时候比硬盘要小,比硬盘要小。啊,那如果说给我来500个g的一个内存行不行?哎,那是不行的,为什么不行呢?因为内存它的访问速度是高于硬盘的,所以它的造价就比较高,造价一旦高,那我们太大的空间我们买不起了,否则这个电脑贵的压根儿就没人能买得起了,对不对?三四千,四五千,五六千就买不到一个电脑了,对不对?一个电脑可能哎几万,对吧?啊,几万几十万,对吧?所以一定要注意要在这个地方的内存他的访问速度是高于硬盘的。那在这个地方呢再往上一存呢再往上一层呢叫什么呢?叫高速缓存,高速缓存速度呢比我们的内存的还要高,那其实在我们的电脑上的高速缓存啊可能就几个兆,对不对?几十个兆它比我们的内存的还要小一些啊,还要小一些,那寄存器比我们的高速缓存的还要快啊,访问速度还要快还要快,那大家注意在这个地方呢那访问速度越快,那它的造价是不是就越高?如果造价越高,那它的一个空间大小在我们的设备上是不是就不敢太多了?这个设备是不是就买的起来太贵了,对不对?所以大家注意有这么一个精彩的效果,如果我们说啊,如果我们说从下往上,从下往上,我们看访问速度的话,访问速度是由低到高啊,速度是越来越快,越来越快,但是空间的话由上往下空间是在我们的硬件上是越来越小越来越小,对吧?啊,越来越小大概这么一个情况,当然也等于说老师为什么会有什么寄存器高速缓存的存在,对不对?

啊?寄存器高速化都存在这个地方呢,我给大家简单的介绍一下,在我们的电脑上还有个东西叫什么叫CPU。CPU的叫什么呢?叫中央处理器,对不对?我们要增加这样的理解,对吧?叫中央处理器,那这个中央处理器是干什么的呢?大家注意我们要在计算机上进行一系列的运算的时候呢,其实啊我们的我们的计算机里边儿要进行一系列的运算的时候呢,我们其实是怎么做的呢?我们说首先你要从内存里面儿拿数据到我们的,你要从内存里边儿哪个数据啊。我们的这个地方呢还不能用它,你要从内存里面儿哪个数据到哪里去呢。到我们的啊,到我们的CPU啊,给我们的CPU,让我们的CPU的进行很好的一个计算啊,从内存里面去拿啊,从内存上去拿,早期到我们这个计算机出现的时候,早期特别早期的时候,当我们计算机出现的时候呢,内存的访问速度,啊,内存的访问速度呢。哎,它和我们的CPU处理数据的速度是比较搭配的啊,CPU说内存能拿多快我就能处理多快,但是后来随着这个计算机的发展,让我们CPU的处理速度,CPU去处理数据的速度越来越快,越来越快,啊,越来越快越来越快,那这个时候就有一个问题出现了,CPU的处理速度越来越快,但是内存的访问速度却跟不上内存的访问速度却跟不上啊,内存的访问速度呢相对来说还是比较慢的啊,那怎么办呢?有人就想说诶,那内存的访问速度如果比较慢的话,内存的访问速度如果比较慢的话,那CPU的处理速度再快,是不是整体计算机的处理速度也跟不上了。那后来有人想,那是这样吧,我们在计算机里边儿再给一些更快的设备,比如说高速缓存,再比如说寄存器。

因为他们频繁大概的使用嘛,那怎么办呢?我们就想说那能不能把a放到寄存器里边儿去?怎么怎么把a放到寄存器里边儿去呢?那c给出一种解决方案是这样的,register他们给出了这样一个关键字,register往这儿一放,register in a就是说我把a给大家定义成一个寄存器变量。把a定义成寄存器变量,寄存器变量把a定义成寄存器变量,当然这个定义只是一个定义作用,建议把a定义成寄存器变量。为什么是建议的一个作用呢?大家想象一下,如果啊我们在这个地方代码里边儿只要写上register a就放到寄存器里边儿去了,那大家想象一下,所有程序员写代码的时候都觉得自己的这个这个变量的特别重,好了,给变量的都加上register,你想象一下我们的代码里边儿出现成千上万个寄存器变量,那到底把哪一个放到寄存器里边儿去呢?这个时候是不是形成了一个问题啊?所以啊我们的寄存器在我们的计算机上是有限的,可能在我们的计算机上只有几十个寄存器,对不对?啊,几十个寄存器,那这个时候没有那么多寄存器可以使怎么办呢?好了,那这个时候呢这个register的关键字仅仅是建议把a放到寄存器变量里边儿去,但是不是最终真的把这个a放到寄存器变量里边儿去,这个是取决于谁呢?取决于编译器会自己去判断能不能要不要把这个a能放到计算器里边儿去,大概就这么一个意思。好,那这就是我们register关键字的一个解释啊,希望大家能够理解啊,后期我们会慢慢增加它的理解,好吧?

剩下的之后会写。

typedef:类型重定义

比如:unsigned int num1 = 20;

那么typedef unsigned int u—int;

这样u—int num2 = 0.

意思是给unsigned int起一个别名,用这个别名去声明起同样效果。

static:用来修饰变量和函数

void test()

{

int a = 1;

a++;

printf("a = % d ", a);

}

int main()

{

int i = 0;

while (i < 5)

{

test();

i++;

}

return 0;

}

如果开始进行程序,那么进入程序之后声明了一个i之后进入will的那个循环体,然后i等于零,i小于五符合条件,那么就会碰到遇到这个test函数,test函数遇到后就会跳转到上面的这个void test函数这块,进入之后它就会创立一个a这么一个变量,a等于1,然后a++加一之后a等于2再打印,所以说就会打印出2,打印出2后再回来到i++,所以i之前等于0,i++之后就会变为1,然后再开始往上找while的这个判断条件,i等于1, 1仍然小于5,那么再到t的函数的时候又会上去,但是又会上去就需要注意到一点。再上去之后我们再去考虑这个程序的话,它会再次声明一个a,a被赋值为一,那么也就是说我们又重新来了一遍,a又被赋值为一,然后呢a++输出2,然后在下面i++,i等于3,3还小于5,再碰到test又回去,a又建立了一次,然后被赋值为1,循环往复,我们会一直到i等于5的时候停止这个循环程序结束。

在int a前加一个static,会使变量会变为一个静态的局部变量。这样输出的结果就是23456.也就是说a赋完新值后会保持这个值,下一次在进入test函数后,2++,a的值不销毁。所以得出结论:static修饰局部变量,变量声明周期变长。

修饰全局变量时,先创建一个新文件。add.c

int g_val = 2021 放入一个变量,然后回到之前的程序。

用extern来引用这个外部的变量

int main()

{

extern int g_val;

pritnf("%d ", g_val);

return 0;

}

会输出2021这个数字。extern可以引用外部变量来提供给所在的程序。如果给g_val前面放上static,static int g_val = 2021。再次引用程序就会报错,变量无法被引用。那么结论:stati修饰全局变量,改变了作用域,使其只能在源文件内使用。

它还可以修饰

int main()

{

int a = 10;

int b = 20;

int sum = Add(a, b);

printf("%d ", sum);

return 0;

}

再在其他文件声明这个add函数

int Add(int x, int y)

{

int z = x + y;

return z;

}

回到前面的程序,要用extern来引用

extern int Add(int, int);

只需要这样声明即可,放在int main前面,即可输出结果,如果在extern前加static,那么就会出错,找不到这样的函数。那么结论:修饰函数,改变函数的连接属性。一个正常的函数拥有外部连接属性。

#define定义的常量和宏

常量说过,来说说宏。

#include <stdio.h>

#define MAX 100 //当程序再遇到MAX时,就会自动变为100.也可以定义宏,宏是带参数的。

一个新程序:

int MAX (int x, int y)

{

if (x > y);

return x;

else

return y;

}

#define MAX(X, Y) (X > Y? X : Y)

int main()

{

int a = 10;

int b = 20; //用宏的方式来做加法

max = MAX(a, b);

printf("max = %d ", max);

return 0;

}

运行之后就出现了20的值。

指针

指针的讲解需要用到内存的概念。

int a = 10;

int* p = &a; //int*是p的类型,p是指针变量,p里储存着a的地址。如果想找到a,那么:

*p //这里用到了之前没有说过的*。*是解引用操作符,*p就可以找到p指向的变量。*p = 20 意思就是a被赋值了20.

int a = 10;

int* p = &a;

*p = 20;

这样就可以理解*操作符了

结束。

经验分享 程序员 微信小程序 职场和发展