写在前面

我们正式开始接触到C语言,这是我在学习过C语言后重新写的博客,我把之前的稍微优化了一下,希望能用更加朴素的语言和大家分享,我希望给大家带来一个可以看的懂,理论和实践并行的内容.当然里面也会存在一些错误和不恰当的地方,还请诸位指正.

为何学习C语言

我想从两个方面和大家分析学习C语言的必要性和好处.

语言层面

我们先来下一个结论 C生万物,编程之本, 很多人学习计算机都是从C语言开始的,它是长远IT职业发展的首选,C语言是母体语言,是人机交互接近底层的桥梁 ,学会 C语言,相当于掌握技术核心 . IT行业,一般每10年就有一次变革,40年间,在 TIOBE 排行榜中,C/C++位置长期霸占前三名,没有丝毫撼动,可谓经典永不过时!

个人层面

在当今社会,技术不断的发展和更新,语言更是层出不穷的出现,C\++、Java、、python、go.语言实在是太多了,那么我们为何还要学一门很老的语言,我们学习最新的语言不是可以更好的适应当前技术的迭代吗?

每个人都有每个人的理解,首先我来说一下自己的观点.和大多数人一样,我接触的第一门语言就是C语言,那时的我感觉内容多,而且还很难理解,尤其是后面的指针一直在困扰着我,但是当我在后面逐渐学习的其他语言后,C语言的很多理念出现在其中,尤其是一脉相承的C\++.C语言的学习可以大大提高我们学习其他语言的能力.

初识C语言

我想分为两个博客的内容和大家整体的过一下C语言的基本知识,这样我们看别人的代码可以看的懂.我认为大家对他有一个认识是非常重要的,这样即使我们深度不够,也有往下探究的欲望.

什么是语言

在现实生活中我们可以很容易的知道人与人交流是通过语言来进行交流的, 人和人可以用汉语,英语,俄语...进行交流,那么人和计算机呢?或者说计算机和计算机是通过什么语言交流的?这就是计算机语言. C语言是常见的一种计算机语言,每一个语言都有自己的优点,也有自己的缺点,C语言同样如此,相比较于其他的语言,C语言更加适合底层开发, 注意C语言是适合底层开发,不意味着只能干,我们也可以使用C语言做上层的业务.

标准

什么事物要想发展要好,必须要有标准.那么什么是标准,在早期我们是通过二进制编程的,,很多人要查手册,这里很难,所以那个时候一般研究这些的都是都是科学家.此时有很多科学家觉得我们使用二进制是在是太麻烦了,受不了了,我们给二进制序列起一个名字,例如张三和身份正好对应,我们把这些名字称之为助记符,后面又发展成汇编语言,B语言,C语言和后面的很多语言.

C语言很优秀,很多厂商会对C语言进行定制,自己增加自己的语法,这个时候就出现了差异,这就是杂乱尺寸生,此时又权威的一些人提出了国际标准,也就是K&R标准,这就是标准.后来标准进行迭代,逐渐的迭代出其他的版本,例如流行的C89标准,和后面的C90,C99.主流标准是C89和C90,C99之后都比较少一些,我们主要看C89的知识点.

helloword

我们来认识第一个代码,这是我们几乎每一个程序员都写过的代码.

#include <stdio.h>
int main()
{
printf("hello,world\n");
return 0;
}

初识C语言(上)_局部变量

main

如果你已经尝试了上面的代码,觉得既新奇又饱含疑惑,那么下面我们先来简单的揭开它的面纱.注意,我们找个博客的目的是可以简单的上手C语言,会用就可以了,至于它的原理随着我们学习的深入,我们都会逐渐明白的,所以说不要着急.

<font color = red>我们规定main函数是程序的入口</font>,注意,这里标准直接这样规定的,也就是说我们启动一个程序时,编译器会自动的找到main函数,然后从上往下的开始执行里面的代码.

我们这里需要看一下main函数的大体框架,后面我们要严格按照这个格式来写,至于为什么这里都等到函数那里去谈.

int main()
{
// 代码
return 0;
}

在一些比较老的代码规范里面,还存在下面的写法,这里我们强烈不推荐.,他们实在是太老了,而且看着还很别扭.

void main()
{

}

printf

我们从main入口进入了,现在我们开始在想,我们程序的目的是往屏幕上打印Hello World,所以我们调用了一个函数,函数相关的细节我们会单独分享.这个时候我告诉你在标准库里面有一个printf函数可以帮助我们完成这个功能,我们要用这个函数,这里需要引一个头文件stdio.h,我们通过下面的做法来达到这个目的.

#include <stdio.h>

到这里解决我们大部分疑惑,也可以简单的上手写一些代码了.

#include <stdio.h>
int main()
{
printf("我是C语言的初学者");
return 0;
}

初识C语言(上)_局部变量_02


数据类型

我们都知道,我们可以从不同的角度来描述一个物体,假如说这有一个箱子,我们可以这样描述.

初识C语言(上)_局部变量_03

这里你会发现有不同的数据类型,存在整数和小数,甚至名字是一串字符.我们计算机要模拟世界,那么肯定要提供这些类型,C语言就给我们内置了很多的数据类型,我们先来见识一下.

数据类型

说明

大小

char

字符类型

1 字节

short

短整型

2 字节

int

整型

4 字节

long

长整型

4 字节

long long

更长的整形

8 字节

float

单精度浮点数

4 字节

double

双精度浮点数

8 字节

回答一下下面的问题:

为什么要定义这么多类型?

我们的应用场景是非常复杂的,不同应用场景要求不同大小的空间,比如说,一个人的年龄、身高等变量可以定义成short型,定义成 int型就浪费了空间。

这些类型的大小是什么意思?

根据不同的类型在内存中开辟不同大小的一块空间,每个类型开辟的空间是固定的,至于如何计算,这个我们下面谈

byte & bit

在回答不同类型占据的空间前我们先来看一下计算机里面的一些单位.这里我们用一个宿舍楼来进行举例子.在一所高校中,我们把一栋宿舍楼分成很多个小宿舍,每一个小宿舍都有固定的床位.计算机同样如此,在计算机中,一块很大的内存,我们把他分成很多个小空间,这个空间名字叫做字节(byte),这里我们首先要强调的是<font color = red>字节是内存的基本单位.</font>和每个小宿舍有这个固定床位一样,每一个字节又会被分为八个区域,这个区域叫做比特位(bit),也就是一字节等于八个比特位.

初识C语言(上)_#include_04

sizeof

上面回答了内存的基本单位,这里就理解不同的数据类型占据若干的字节是什么意思了.这个时候我们又在想,我们是不是可以验证一下,你在这里一直给我灌输理论,总是感觉有点不踏实.这里我们就要请出sizeof这个关键字.我们先来解释一下什么是关键字.

我这里直接说我的理解,所谓的关键字是C语言官方给我们提供的,这些关键字有着不同的功能,比如说上面的int,我们可以很清楚的知道int代表的是一个整型.sizeof也是一个关键字,它的作用是计算占据内存空间的大小,单位就是字节.后面我们会遇到很多关键字,我们用一个谈一个.现在开始验证一下这些类型的大小,你会发现printf又出现了新的用法,这个后面会谈到,先暂时这样用着.

#include <stdio.h>
int main()
{
printf("char %d\n", sizeof(char));
printf("short %d\n", sizeof(short));
printf("int %d\n", sizeof(int));
printf("long int %d\n", sizeof(long int));
printf("long long %d\n", sizeof(long long));
printf("float %d\n", sizeof(float));
printf("double %d\n", sizeof(double));
system("pause");
return 0;
}

初识C语言(上)_#include_05

常量

生活中的有些值是不变的(比如:圆周率,性别(?),身份证号码,血型等等),有些值是可变的(比如:年龄,体重,薪资)。 在C语言中,我们会学习到变量,常量,作用域,生命周期......等概念,我们不由得发出疑问,什么是变量,为什么要有变量?这些都是我们需要处理得疑惑.我先谈谈常量,后面再说说变量。所谓的常量就是不可再次修改的数据.它有下面的几种分类.

  • 数值常量 1,2,3...
  • 字符串常量 "abcd","defcbg"

这里面我重点谈谈字符串常量,在C语言中,存在一个字符串常量池,这个我们等到操作系统再谈,像"abcd"就是其中的一部分,要是我们想要修改"abcd"变为"bbcd",这是做不到的,有的人可能会感到疑惑,这不是很简单吗,我们只需要把a修改成b不就完成了吗?但是这只是象,"bbcd"也是字符串常量池的一部分,我们所谓的修改,就是更改指针所指向的地址(指针后面谈).

#include <stdio.h>

int main()
{
char* pa = "abcd";
printf("%p\n", pa);

pa = "bbcd";
printf("%p\n", pa);
return 0;
}

初识C语言(上)_全局变量_06

常量分类

上面的太笼统 这类简单的说一下,在C语言中我们将学习不同的常量.

  • 字面常量 就是字符
  • const 修饰的常变量
  • 枚举 后面谈
  • #define 定义得的标识符常量

注意:const是一个关键字,这个关键字作用是很大的,我们后面会重点分析.

变量

简单得来说,变量就是可以修改得量.变量不同于常量,它可以被修改的\.例如int x = 10,x可以修改为20,但是我们不能把常量1修改成常量2.这就是变量定义.<font color = red>在计算机中,变量是一个在内存中开辟特定大小的空间,用来保存数据. </font>

定义变量

这倒是很简单,就是<font color = blue>类型 变量名 = 初始化的值</font>.这里我们需要谈一下什么是变量名,前面我们描述箱子的时候,谈到了长度,我们用L表示,此时这里就可以认为L就是一个变量.

int a = 10;          // 定义一个整型变量a  并初始化为 10
double b = 10.2; // 定义一个双精度浮点数变量b 并初始化为 10

变量的分类

变量的分类主要分为两大类,我们尽量不要使用全局变量.

  • 全局变量
  • 局部变量

局部变量

局部变量:包含在代码块中的变量叫做局部变量。局部变量具有临时性。进入代码块,自动形成局部变量,退出代码块自动释放.(网上很多说函数中的变量是局部变量,不能说错,但说法是不准确的),下面的a和d都是局部变量.

int main()
{
int a = 10;
double d = 11.01;
return 0;
}

这里来个复杂的,这里就可以验证一下局部变量具有临时性,这里的临时性可以认为对标下面的作用域和生命周期.

#include <stdio.h>

int main()
{
int a = 10;
{
int x = 20;
printf("x = %d\n", x);
} return 0;
}

初识C语言(上)_全局变量_07

这里的临时性就可以通过下面的代码验证出来

#include <stdio.h>

int main()
{
int a = 10;
{
int x = 20;
printf("x = %d\n", x);
}
printf("x = %d\n", x);

return 0;
}

初识C语言(上)_#include_08

局部变量如果不进行初始化,那么根据编译器的不同,我们拿到的是随机值,甚至严格的编译器都不会让我们使用.

初识C语言(上)_局部变量_09

我们在测试一下gcc编译器,这里看看有什么不同.看来gcc是没有VS严格的,但是我们要按照最标准的来,严格遵守变量被定义一定要初始化.

初识C语言(上)_全局变量_10

全局变量

这里我想和大家谈谈全局变量,这个有一点重要.所谓的全局变量,全局变量具有全局性 , 我们可以认为是在main函数外边所定义的变量,一般按照<font color = bluee>g_变量名</font>的格式来走,当然,也可以不按.

#include <stdio.h>

int g_key = 20; //全局变量
double g_val = 10.00;

int main()
{

printf("%d\n", g_key);
printf("%d\n", g_val);
return 0;
}

初识C语言(上)_局部变量_11

上面我们谈到了局部变量不进行初识化是随机值,那么全局变量呢?这是很简单的,我们直接给一个结论,全局变量定义起来即使我们不初始化,他也是固定值,是0.这里只验证VS.

int a;
int main()
{
printf("%d\n", a);
return 0;
}

初识C语言(上)_全局变量_12

注意,如果你坚持看我后面写的博客,就会发现我们很少使用全局变量,它是有一定的缺陷的,等到后面我们会专门谈的.

局部优先

大家看一下下面的代码.<font color = red>如果全局变量和局部变量同名,编译器优先使用局部变量,这就是局部优先原则.</font>

#include <stdio.h>
int a = 10;
int main()
{
int a = 0;
printf("a = %d\n", a);
return 0;
}

初识C语言(上)_全局变量_13

变量的使用

我们先来简单色的通过格式化输入输出来分析一下变量是如何被我门使用的,这些都是很简单的.

printf

这里我们需要再次谈一下printf函数,上面我们已经使用过它的用法了,可能大家会有一些疑惑,这里需要具体的分析一下这个函数.

printf()函数是我们经常使用的的函数之一,他的作用就是将我们想要的数据输出到指定位置,这里的指定位置包含屏幕,我们先使用一下

#include <stdio.h>

int main()
{
int a = 10;
printf("%d\n", a);
return 0;
}

初识C语言(上)_全局变量_14

这里我们可以看到,我们使用了printf()函数

printf("%d\n",a);

这里有几点要说一下

  • % 被称为 "转换说明",所谓的转换说明就是将数据按指定的格式显式出来
  • %d是指将a的值以十进制的形式打印来,例如 %o :打印八进制、%x 打印十六进制.....

数据输出的格式与很多,下面我列出一张表

X

例子

说明

d

%d

打印int型,默认1

f

%f

打印float型,小数点后默认6位

e

%e

以科学计数法的形式打印,小数点后默认6位

g

%g

以科学计数法或者float型打印,方式看g的大小选择

scanf

我们在想既然变量是可以变化的,我们总不能把先要的值全部列出来吧,我们如果手动输入该如何做到呢?这里给大家简绍一个scanf函数.

和printf() 一样,scanf()也是存在特定的格式读入,这里先给出个例子,我们一起来看看

#include <stdio.h>

int main()
{
int a = 0;
scanf("%d", &a);
printf("%d\n", a);
return 0;
}

初识C语言(上)_局部变量_15

作用域&生命周期

这个一直是一个比较容易模糊的点,有很多人对他们的区别可能分不太清楚,一般我们能分辨清楚就可以了

  • 作用域 变量可以被使用的地方,就是作用域
  • 生命周期 变量开始开辟空间 到 空间销毁

这里我先给出点结论,适合大部分情况.局部变量的作用域和生命周期是在局部变量所在的代码块中,除了代码块就不可以了.全局变量的作用域和生命周期是整个程序.