从这里开始,记录我每次的学习。
目录
一、什么是C语言
人和计算机交流的语言,比如C语言,Java,python。语言的发展历史上,最初计算机能够识别的语言是二进制语言,想让计算机工作,就需要敲入许多的二进制数字来命令,这就要求记住各种命令对应的二进制代码,那时候很多人只能按照手册来编写代码,能编写这种二进制代码的大多数是科学家。后来通过简化,将一个功能对应的二进制代码命名成一个易懂的表达方式,比如加对应的二进制数字代码,将其表达为add,而像add这样的就被称为助记符,用助记符表达的语言就叫做汇编语言。但是这种代码仍然麻烦,需要继续进化。这之后出现了更高级的语言B语言,B语言基础上有进化出了C语言,C语言的基础上出现了C++。到了C语言这一步,就属于高级语言了,现在写C语言已经变得很容易,人们都可以学习一些C语言,学习门槛也在降低。从最早期的低级语言 纯二进制代码发展到了C语言,语言发展就是这样一个过程。
C语言也有一个逐渐发展的过程,从不成熟到成熟,再到达现在流行的程度。早期不成熟的阶段,各家公司都会做出自己的一套C语言代码,但是互相不流通,自创的代码太多。这样的结果对于公司的发展和C语言的普及很不利,一个语言要想真是普及大众,则必须有一套标准,就想英语一样,我们可以在维基百科上看到英语的国际标准就是英式英语,世界上也有一些英语的标准,一个语言的流通是必须要求标准的。在大概1989美国国家标准协会推出了ANSI C标准,这个标准也被称为C89,1990年国际标准化组织ISO认可了这个ANSI C标准,并把它彻底定尾国际标准。也被称为C90.后来也出现了一些别的标准,但是因为无法流行起来,很多编译器不支持这些标准,所以最后都消失了。这样,ANSI C标准下,每个人写的C语言代码都可以通用,C语言也逐渐发展成熟了。
二、第一个C语言程序
这里要编写一个简单的程序。本人用的是ubuntu系统,gcc编译器,在这里不做安装教程,可自行搜索。同样,也有其他的编译器,比如Visual Studio Code编译器。这里写一个程序员开始学习时都会学到的代码——hello world。
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
从头开始说起。main函数是一个主函数,是程序的入口,意思是程序会调用这个main函数来开始执行程序。程序不能没有main函数,否则计算机不清楚程序应该从哪里开始。如果写多个main函数的话,同样不行,因为这时程序从任何一个main函数开始都可以,所以产生了歧义,无法正确开始程序。main函数是程序的入口,有且仅有一个。main函数的框架:
int main()
{
return 0; //返回 0
}
return 是返回的意思,int是整型。int用在main前面意味着main函数调用之后返回一个整型值。所以返回的0和前面的声明呼应了。类型决定了数据的内容以及可能发生在这个数据上的操作。在return 0前面可以写入要执行的命令,比如之前的printf("hello world"); printf是打印函数,printf的括号里要用双引号来包含你想输出(打印)的内容。
printf函数是一种库函数,是C语言函数库里的函数,是C语言本身提供给程序员的函数,想要用C语言的库函数,必须要有头文件。在上面的程序中,#include <stdio.h>就是这个库函数的头文件,它包括很多库函数,其中就有printf函数。解释一下这个头文件,std意味standard,i-input,o-output。当我们想输出或输入某些代码时,都要用上stdio。
三、数据类型
char signed char unsigned char
signed short int signed int signed long int
unsigned short int unsigned int unsigned long int
float double long double
这些都是关键字,它们不能作为变量名来使用,接下来有实际使用中的对应的关键字。char表示字符, int代表整数,但只有char和int可以用作关键字,其它数据类型,如数组,指针和结构,都是从基本类型派生而来的,它们将在后面的笔记中出现。
通常,关键字signed不被使用,signed int相当于int,因为更短的名称更容易输入,所以通常使用int。然而,char类型在这方面是特殊的。此外,关键字short int,long int, unsigned int也可以,而且通常是,分别缩短为short,long, unsigned。signed本身相当于int,但是在上下文中很少使用。根据这些约定,我们得到一个重新的表。
char signed char unsigned char
short int long
unsigned short unsigned unsigned long
float double long double
这里学习几个类型。
char //字符数据类型
short //短整型
int //整型
long //长整型
long long //更长的整型
float //单精度浮点数
double //双精度浮点数
CHAR、
从char开始。写下这样一个小程序。在C语言中,要用单引号引起一个字符
int main()
{
//printf("hello world\n");
char ch = 'A';
return 0;
}
如果想要储存字符A的话,就需要向内存申请一块空间。而char就可以起到这样的作用。代码 char ch = 'A' ,我们向内存申请了一部分空间,这份空间名称就是ch,而其中存储的字符A是char类型的字符。继续代码,试着打印这个字符'A'。
printf("%c\n", ch); %c表示打印内容以字符格式打印;\n是换行符,意为,打印完这个字符后要换行;前面是打印格式,后面是打印内容,这是printf的语法形式。意思为以%c的格式来打印ch,ch中有'A',所以会打印出字符A。
INT、
整型同字符一样。看代码
int age = 20; //创立了一个int类型的变量age,age在内存中占用一定空间,存储了十进制整数20。
printf("%d\n", age);
%d用于打印十进制整数.其他整型也是如此用法,不再往下介绍。
FLOAT、DOUBLE
float f = 12.0;
printf("%f \n", f);
%f用于打印浮点常数——打印小数。浮点常数的写法后期笔记中出现,这里只要清楚用小数形式写即可。
double类型的数据,比如double d = 10.0,用%lf格式打印更适合,%lf表示以双精度浮点常数格式打印,%f则是单精度。
写到这。来看看整型和浮点型之间的差异。有很多差异,其中一个就是占用内存的空间的不同。在这里引入一个函数sizeof。顾名思义,可以表示一种大小,获取一个对象(数据类型或数据对象)的大小(占用内存的大小)。写代码
int main()
{
//printf("hello world\n");
//char ch = 'A';
printf("%d\n", sizeof(char));
return 0;
}
这样,就可以打印出char类型向内存申请了多少空间,这里结果是1字节。我列出来这些结果。
char ——1
short——2
int——4
long——4或8,4/8
long long——8
float——4
double——8
所有的结果。这里插播一个点,同一类型signed(有符号),unsigned(无符号)占用字节数相同。上面提到了字节,我们需要看一下字节具体是什么单位。在计算机中的单位里面,最小的单位是bit,比特位。往上,byte,也就是字节,更通俗点,B。往上,kb,mb,gb,tb,pb。从bit开始说起。计算机通电后产生正电和负电,电流要被转换成数字信号,正点转为1,负电转为0。如果要存储1这个二进制数字,那么计算机就会用一小块空间,只存储1,这快空间是1bit。存储0页一样,都在存储一个二进制数字,都只用1bit。1个字节(byte)等于8个bit,1kb等于1024bit(B)。。。。。。 那么我们可以得出,char可以存放8个比特位,也就是1个字节,short可以放16个比特位,也就是2个字节。假如声明一个变量为char,8个比特位,那么
00000000
00000001
00000010
00000011
00000100^
00000101
00000110
。。。。。
11111111
等等,总共可以存放2的8次方个二进制数字。关于二进制及其计算在这里不记录了。 上面的二进制数转换为十进制的话,则为0,1,2,3,4,5.......2^8-1,总共能放2^8个二进制数字,表达的范围就是 [0,2^8-1]。我们应该预估好要表达的变量的大小,来运用合适的关键字来声明变量,不让空间浪费。
之前的long类型是4或8,在64位机器里是8,32位是4。
写一个代码:
int main()
{
//printf("hello world\n");
//char ch = 'A';
//printf("%d\n", sizeof(char));
short age = 20; //向内存申请2个字节用来存放20
float weight = 110.4;
return 0;
}
如果这样运行的话,可能会出现警告。因为这样的小数默认为double类型,这样做会丢失精度。不过不是大问题,在数字后加上f就可,110.4f,这样就可以明确指定110.4为float类型。
四、常量、变量
定义变量的方法、
定义变量很简单,之前的short age = 20;就是在定义变量,很简单。
变量的分类、
变量分为局部变量和全局变量。
int a = 20;//全局变量:定义在代码块(大括号里面的内容)之外的变量
int main()
{
int a = 10; //局部变量: 代码块之内或者函数内部的变量
printf("%d\n", a);
return 0;
}
这时候如果运行,结果是10。局部和全局可以共存,但是如果变量名一样,那么容易形成bug。名字相同时,局部变量优先,所以尽量不要全局局部同名。其实这个事实很容易理解,声明一个int类型的a,并给他赋值20;进入代码块里,此时a是20,代码又将a赋值为10,然后执行printf语句,打印出a,所以此时结果为10。再看代码:
int main()
{
{
int a = 10;
}
printf("%d\n", a);
return 0;
}
此时如果运行,则会出错,printf所在的大括号里没有a,a是一个局部变量。假如
int a = 10;
int main()
{
printf("%d\n", a);
return 0;
}
此时就打印出10了。
变量的使用、
这里举个例子来说明
int main()
{
int num1 = 1;
int num2 = 3;
scanf("%d%d", &num1, &num2);//输入函数,两个数则用两个% d,之间不需要空格,要输出的数据存放在num1和num2,这时候要用取地址符号& ,& 可以把变量的地址表示出来,这样数据就可以放进去了。
int sum = 0;//声明sum,用来存储和的数字
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
看起来没用问题,但是这样运行后,就会出现一个错误。在类型前面缺少分号。这个问题只是一个小问题。C语言语法规定,变量要在当前代码块的最前面定义。而c++则不需要,等用的时候再定义也没问题。把sum的声明放到scanf前面即可,此时就没错误了。执行,我们输入两个数字,这两个数字分别放在num1和2中,之后sum = 也打印出了和。
变量的作用域和生命周期、
这个变量可用的地方就是它的作用域。
int main()
{
{
int a = 10;
}
printf("a = %d\n", a);
return 0;
}
这个a的作用域就在这个代码块里。这样打印不出结果,如果打印函数放在a所在的代码块里就可以运行了。
局部变量的作用域就是变量所在的局部范围。全局变量就是整个程序。
可以输出结果。这是全局变量。全局变量范围很大,无论接下来的代码出现什么,printf会一直输出全局变量,当然除了有局部变量。如果我们在另一个程序里声明了一个变量,那么在这个程序里直接printf没有用,会出错,为声明的标识符。在printf前面加上一个语句,extern int 变量名,这样就可以引用外部变量了。这个是需要记住即可,无需多想,之后再说。
对于局部变量的生命周期,从进入作用域开始到作用域结束。
int main()
{
{//开始
int g = 0;
printf("%d\n", g);
}//结束
printf("%d\n", g);
return 0;
}
全局变量的生命周期就是整个程序。
代码一定要写头文件,本文中只是写了main函数后的,但并不代表不用写头文件。没有头文件,任何函数皆无用。
结束。