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

目录

一、函数

二、数组

三、操作符

算术操作符

移位操作符

位操作符

赋值操作符

单目操作符

sizeof

~

--,++

关系操作符

逻辑操作符

条件操作符

逗号表达式

四、常见关键字

先写几个

typedef:类型重定义

static:用来修饰变量和函数

#define定义的常量和宏

五、指针


一、函数

 看一个程序:

int 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);
    printf("sum = %d\n", sum);
    sum = Add(a, b);
    printf("sum = %d\n", sum);
    return 0;
}

       基于之前的一个加法函数做了增添。之前只用了num1, num2,如果想要再算a,b,按照之前的思路,还需要再写代码来一步步算。现在我们可以定义一个加法函数,在程序里使用这个加法函数就可以了。在main之前,我们定义了函数,大括号里的是函数体,小括号里的是函数的参数,int是它的类型。整个过程是,进入main代码块里,引用了add函数,上面的x,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\n", arr[5]);  这时打印出的是6。访问数组的方式是用下标访问。现在要打印数组里所有的数字,也就是说0-9全都要打印出来,这里就可以用循环体。

    int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int i = 0;
    while (i < 10)
    {
        printf("%d\n", arr[i]);
        i++;
    }
    return 0;

这样就能打印出所有了。

三、操作符

算术操作符

+ -  * / %

       加 减 乘 除 模。模运算是取余数的算术法,叫做取模。int a = 7%3   得出来的数值是1;/是取商,7/3就是2。

移位操作符

      >> , <<。分为右移和左移。这个移是移了二进制的位。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 a = 3;
    int b = 5;
    int c = a & b;

   a  011

   b  101

       001 

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

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

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

赋值操作符

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

上一篇记录中提到过赋值不是等于。这里都是赋值操作符。a += b以及a = a + b这两种写法完全一样。其他操作符不必多说了。可以这两种都写出来就知道什么意思了。

单目操作符

!               逻辑操作符

-                  负值

+                 正值

&                 取地址

sizeof          操作数的类型长度

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

--                 前置、后置---

++               前置、后置++

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

(类型)     强制类型转换

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

int a = 10;

int b = 20;

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

    int a = 10;
    printf("%d\n", a);
    printf("%d\n", !a);

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

sizeof

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

    int a = 3;
    printf("%d\n", sizeof(a));

       此时会计算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 = 10;
    int b = ~a;
    printf("%d\n", b);

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

a:0000000000000000

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

--,++

    int a = 10;
    int b = a++;
    printf("a = %d, b = %d\n", a, b);

       ++在a的后面,是后置,后置的用法是a先赋值给b后,再++;先使用再加。前置++是++a,先加再赋值。这是前置和后置的区别,--也同样。可以看出来,这里的操作只针对这一行,之前的像line++,意思就是先用line做一定的操作,再把它+1,但是这一行并没有操作,所以就直接+1了,这时候++line效果一样。关于强制类型转换符:

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 = 0;
    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。在C++11中这个还有奇用。

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

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

       好,这个时候呢我们达成了这样一个想法,说未来你的CPU处理的数据,你去哪里拿?你去寄存器里边儿去拿你的数据,这样速度是不是更快了。因为寄存器的访问速度更快嘛,我去寄存器里去拿,那这个时候访问速度更快了。但是呢我们说寄存器的没数据啊,那怎么办呢?先让内存的数据代表高速缓存,高速缓存的数据加到内存里边儿去,然后我们CPU在从这个寄存器里边儿去拿数据,当我们有一次在寄存器怎么没有拿到我们想要的一个数据的时候,我再向下去访问,我再去高速缓存和内存去访问,所以其实我们每次CPU处理数据的时候都去寄存器里边儿去拿,当我拿不到数据的时候,我再去下面的空间里面去拿,这样我们计算机的整体速度时候就上去了。这是我们计算机里边儿存在这样一个存储体系的一个基本原因。当然寄存器这个关键字就是我们刚刚写的register。这样一个关键字,对吧?register这样一个关键字。那寄存器的访问速度那么快的话,那我们未来呢,我们写代码的时候就允许这样去写代码吗?怎么去写代码呢?诶,我们这样写,你看这是我的一个main函数,那写什么代码呢?我说int a = 10 而这个10未来会帮我们频繁大量地使用时候,那想象一下,每次我去访问a的时候去内存里边儿去拿是不是速度比较慢?

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

typedef:类型重定义

比如:unsigned int num1 = 20;

那么typedef  unsigned int  u—int;

这样u—int num2 = 0。

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

static:用来修饰变量和函数

void test()
{
    int a = 1;
    a++;
    printf("a = %d\n", a);
}

int main()
{
    int i = 0;
    while (i < 5)
    {
        test();
        i++;
    }
    return 0;
}

如果开始进行程序,那么进入程序之后声明了一个i之后进入will的那个循环体,然后i等于零,i小于5符合条件,那么就会碰到遇到这个test函数,test函数遇到后就会跳转到上面的这个void test函数这块,进入之后它就会创立一个a这么一个变量,a等于1,然后a++加1之后a等于2再打印,所以说就会打印出2,打印出2后再回来到i++,所以i之前等于0,i++之后就会变为1,然后再开始往上找while的这个判断条件,i等于1,1仍然小于5,那么再到t的函数的时候又会上去,但是又会上去就需要注意到一点,再上去之后我们再去考虑这个程序的话,它会再次声明一个a,a被赋值为1,那么也就是说我们又重新来了一遍,a又被赋值为1,然后呢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;
    printf("%d\n", g_val);
    return 0;
}

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

它还可以修饰 

    int a = 100;
    int b = 200;
    int sum = Add(a, b);
    printf("%d\n", 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,那么就会出错,找不到这样的函数,也就是说static不是在int Add之前写的,而是在引用时写的。那么结论:修饰函数,改变函数的连接属性。一个正常的函数拥有外部连接属性。

#define定义的常量和宏

常量说过,来说说宏。
#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;//用宏的方式来做加法
    int max = MAX(a, b);
    printf("max = %d\n", max);
    return 0;
}

运行之后就出现了20的值。但是宏是直接替换,也就是把定义的东西直接搬过来,这个之后写。

五、指针

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

int main()
{
    int a = 10;
    int* p = &a;//int*是p的类型,p是指针变量,p里储存着a的地址。如果想找到a,那么:*p  这里用到了之前没有说过的*。*是解引用操作符,*p就可以找到p指向的变量。*p = 20  意思就是a被赋值了20.
    *p = 20;
    return 0;
}

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

结束。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值