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\n", 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\n", 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\n", 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.
赋值操作符
= += -= *= /= &= ^= |= >>= <<=
上一篇记录中提到过赋值不是等于。这里都是赋值操作符。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 main ()
{
int a = 3;
pritnf("%d\n", 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\n", b);
~按二进制位取反。具体来看:
a:0000000000000000
按位取反后,就是1111111111111111,数字个数并不是32位,只是要表达这种转换。但是如果打印,结果就不是1111111111111111对应的二进制数字。这里涉及到原码,反码,补码。二进制数字最左边的数字代表正负,1为负,0为正。负数在内存中存储的时候,存储的是二进制的代码。所以此时这个111111111111111是补码。而要打印出来,打印的是原码,所以减一,在取反,就得到1000000000001,这样输出的结果就是-1。
--,++
int main()
{
int a = 10;
int b = a++;
printf("a = %d, b = %d\n", 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的处理速度再快,是不是整体计算机的处理速度也跟不上了。那后来有人想,那是这样吧,我们在计算机里边儿再给一些更快的设备,比如说高速缓存,再比如说寄存器。
好,这个时候呢我们达成了这样一个达成了这样一个想法,说未来你的CPU处理的数据呢你去哪里拿你CPU想出处理数据,你去寄存器里边儿去拿你的数据去去去拿从寄存器里边儿去拿的话,大家想象一下这个速度是不是更快了。因为寄存器的访问速度更快嘛,对不对啊,我去寄存器里去拿,那这个时候访问速度更快了。但是呢我们说寄存器的没数据啊,那怎么办呢?先让内存的数据代表高速缓存,高速缓存的数据加到内存里边儿去,然后诶我们CPU在从这个地方寄存器里边儿去拿数据,当我们有一次在寄存器怎么没有拿到我们想一个数据的时候呢,我再向下去访问,我再去高速缓存和内存去访问,这样的话大家发现没有发现,其实我们每次CPU处理速度处理处理数据的时候都去寄存器里边儿去拿,当我拿不到数据的时候,我再去下面的空间里面去拿,这样我们计算机的整体速度时候就上去了。诶,这是我们计算机里边儿存在这样一个存储体系的一个基本原因。当然我们在这个地方就给大家介绍清楚了这个地方存在寄存器的一个原因啊,寄存器啊,当然寄存器这个关键字啊就是我们刚刚写的register。这样一个关键字,对吧?register这样一个关键字。好,同学们注意。那我们说寄存器的访问速度那么快的话,那我们未来呢,诶我们写代码的时候就允许这样去写代码什么?怎么去写代码呢?诶,我们这样写,我说,你看这是我的一个梦函数,这是我的一个梦函数啊,梦函数的访问速度呢。哎,不对啊,梦,这是我的一个梦函数,我们在梦函数里面儿去写代码,那写什么代码呢?我说印的a等于算一个时而这个十未来会帮我们频繁大量的使用频繁带来的时候,那大家想象一下,每次我去访问a的时候去内存里边儿去拿是不是速度比较慢?
因为他们频繁大概的使用嘛,那怎么办呢?我们就想说那能不能把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\n", 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\n", 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\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,那么就会出错,找不到这样的函数。那么结论:修饰函数,改变函数的连接属性。一个正常的函数拥有外部连接属性。
#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\n", 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;
这样就可以理解*操作符了
结束。
C语言学习记录——삼 初识C语言(3)相关推荐
- C语言学习记录-----이 初识C语言(2)
常量. 分类:字面常量,#define修饰的常量,const修饰的常量,枚举常量.字面常量也就是我们很熟悉的常量,比如5,g,这些都是常量,无法被改变,可以直接写出来.之前的int a = 5,a就是 ...
- Fortran语言学习记录
Fortran语言学习记录** ** 今天是2020年4月1日,上午终于把微软的Visual Studio 2013(https://blog.csdn.net/wobckr/article/deta ...
- C语言学习记录(14)英文单词排序 查找最长的单词
C语言学习记录 前言 一直自己没有学习做笔记的习惯,所以为了加强自己对知识的深入理解,决定将学习笔记写下来,希望向各位大牛们学习交流! 不当之处请斧正!在此感谢!这边就先从学习C语言写起,自己本身对程 ...
- C语言入门(初识C语言)
C语言入门(初识C语言) 前言 什么是C语言? 为什么选择C语言? 计算机语言的发展 高级计算机语言中的经典:C语言 初识C语言(正片开始) 一.第一个C语言程序(你好,C语言) 1.1 #inclu ...
- Python语言学习:利用python语言实现调用内部命令(python调用Shell脚本)—命令提示符cmd的几种方法
Python语言学习:利用python语言实现调用内部命令(python调用Shell脚本)-命令提示符cmd的几种方法 目录 利用python语言实现调用内部命令-命令提示符cmd的几种方法 T1. ...
- C语言学习宝典下载,C语言学习宝典
C语音学习宝典手机版是一款很好用的C语音移动学习工具,为用户带来了C语音真题联系及学习课程,让用户可以充分利用碎片时间进行联系.C语音学习宝典手机版还提供了非常强大的手机编程工具,很多代码手机上就能完 ...
- c语言注释语句执行吗,C语言学习笔记之C语言概念解析(附资料分享)每一个语句都必须以分号结尾但预处理命令函数头和花括号“}”之后不能加分号...
[[怪兽爱C语言]C语言学习笔记之C语言概念解析(附资料分享)]https://toutiao.com/group/6582429294901854728/?iid=15906422033&a ...
- c++/c语言学习记录时间帖
双非本科浑浑噩噩过去了,现在双非研一,不想毕业的时候跟大四一样,决定好好学习一门技术,听了一些人的建议,感觉自己研究方向对以后找工作没什么帮助的,在做好导师安排的科研任务的同时,多学一点东西,抓紧ru ...
- 不正经的C语言学习记录(一)
事先声明:我目前学习C语言主要是通过慕课上翁恺老师的课程学习的,所以打算大致按照翁恺老师的课程顺序来记录我对C语言所了解的内容. 首先简述一下C语言的历史:C语言是在上个世纪七十年代开始的,当然,更准 ...
最新文章
- 01 http协议概念及工作流程
- jquery animate函数实现
- linux5启动过程及故障排除
- AI会完美的执行我们设定的目标,但这不是一个好消息
- c# out ref
- 百度地图与HT for Web结合的GIS网络拓扑应用
- VTK:VTK 的相机模型用法实战
- 数据结构与算法之RandomPool结构和岛问题
- Python Data Science的多版本多环境管理工具Anaconda
- 浅谈JavaScript中闭包
- 给Python初学者的入门课程建议
- 使用索引的技巧知识点
- MAC电脑安装window系统(一):双系统安装方法
- Javascript:利用闭包封装模块
- 安装8in1飞行模拟器过程
- php 微信商城 多级分销,PHP多级分销全解密去后门修复版商城源码+分红系统+微信多级分销...
- 再探 Compose 版本的玩安卓
- Carson带你学Android:源码解析自定义View Draw过程
- 教你如何将360全景图免费下载到本地,并生成全景漫游
- 神经网络与深度学习笔记 (五)深层神经网络
热门文章
- 台式电脑计算机能创建新磁盘吗,旧机械硬盘可以装新电脑上吗?台式电脑加新/旧机械硬盘+分区教程(2)...
- python编程能有什么用_近年来,python这么火的原因是什么?python语言能做什么?...
- Google发布AutoDraw堪称美术缺陷者的上帝之手
- 做PPT怎么能少了素材!(收藏的高清图片素材网站二)
- mes系统的价格由哪些因素决定?
- 爬虫学习(2):贴吧之骑马与砍杀2,愿它长寿?
- 蓝桥杯电子类单片机组模块——独立按键(长按与短按)
- java根据月份计算该月天数
- SQL的一对多,多对一,一对一,多对多什么意思?
- 逻辑回归算法——经典的二分类算法