C语言的学习---给我那个亲爱的弟弟
这个学期弟弟在大学里开始了C语言的学习,经常会打电话过来讨论一些问题,一些过来人都会经历的问题,循环 函数 数组 指针。
总结一些自己学习的一些学习心得,希望他能从中学习到一些东西。也以此作为在程序员这条路上的学习过程和经历的总结。
1.我们学习程序设计是为了什么,以及程序是干什么的
其实我们学习程序设计的目的很简单就是让它帮助我们做一些数据的处理,然后把处理的结果返回给我们。
我们给程序一个输入,然后在程序中对我们的数据进行处理后输出给我们相应的结果,我们就可以从这个图中开始学习C语言。首先针对输入开说吧,现在的计算机也没有达到能够完全理解人的思维的程度,所以我们在要求程序帮助我们做事情的时候给他一个他能理解的语言,理想的状况是我们直接输入机器码这样程序就会很好的理解,可惜的是这样就对我们来说太难了。所以那些牛人就发明了一些高级语言,在此想那些发明一种计算机语言的牛人道一声感谢,他们让我们有东西可以搞。为了然计算机里理解我们的输入就有了一些基本的数据类型,整型、浮点型、指针、和聚合类型(数组和结构体) 。其实这些基本的类型还是有一些规律的,千万不要认为这些类型是凭空出现的。为可存储某个变量的地址从而有了指针类型,为了存储一些同种类型的变量从而有了数组,为了将不同类型的一些数据放到一起作为一个整体看待从而有了结构体大概这也是面向对象的源泉吧。从指针作为一种C语言的基本类型,就可以看出学习好指针对学习好C语言有多重要。我想等你应用指针就像应用char、int一样自如的时候你的C语言也就达到了一定的高度。
有了基本的输入类型就解决了我们的输入计算机不能理解的问题,这样就只剩下的计算机对输入的数据进行处理了。恰好C语言中的函数就是干这些活儿的,我们给他一个输入然后返回我们希望的结果:比如你求两个数的和你就可以写一个函数来完成,然后在main函数中调用这个函数
#include <stdio.h> int add(int a, int b); int main() { int a; int b; scanf("%d %d", &a, &b); int sum = add(a, b); printf("sum = %d\n", sum); } int add(int a, int b) { return a + b; }
在这个函数中a,b作为input , 函数add作为我们的process, a+b结果作为我们的返回值。
2.关于变量
一直觉得C语言是由变量和函数组成的,说到C语言中的变量就不得不说他的两个属性:名字和地址。就好比警察叔叔找破坏分子一样可以通过两种方式,一种是通过他的名字,另一种呢就是他的住址。比如定义一个变量 int a = 0,首先计算机会给变量a存放到一个地址,然后将这个地址的值设置为0,之后访问a我们就有了两种方法。如果你打算真心想研究一下变量的的话我觉得他的作用域和存储类型,前者决定了他在程序的那些地方可以使用,后者决定了他们何时创建何时销毁以及他们的生命周期有多长。首先拿他的作用域开说吧。变量的声明位置决定了他有什么样的作用域,具体来说有以下几种作用域:
代码块作用域,在一对花括号中声明的变量,以及函数的形参
文件作用域,在同一个工程中的都可以访问的变量,全局的变量以及在文件中定义的函数
#include <stdio.h> static int sb = 12; int ia = 123; int add(int b, int c) { int sum = b + b; return sum; } int main() { int c = 33; { int dd = 23; int ee = c + dd; } }
上面这个函数里的每个变量的作用域希望你能回答出来,顺便自己查资料了解一下C语言中的static关键字的作用吧。
关于存储区域,每一个变量都有他的存储区域,在了解存储区域之前有必要了解一下程序的地址空间,每运行一个程序操作系统就会加载你程序到相关的位置,以下是你的程序运行时候的地址空间图:
从其中可以看出程序运行的时候,程序的空间分为两个部分,用户空间和内核空间。先阶段的我们只关心用户空间就可以了,上面说过你程序开始运行后操作系统会把程序相应的部分加载到一个空间中,一个程序有几部分你也应该是了解过的。通过程序的地址空间图可以发现变量有一下的存储域:
全局栈:全局变量以及static的局部变量的存储区域,这些变量在程序运行之前创建,在程序的运行过程中一直存在,直到程序运行结束的时候才会销毁。
堆:调用malloc创建出来的变量将存放在该空间上,这个空间是操作系统交给你来管理的,你需要的时候向操作系统进行申请,你实用完成后还是希望你通知操作系统去回收这块内存,养成一个好的习惯。
局部栈:代码块里声明的一些局部变量就将存储在这个区域,存放在局部栈中的变量在出作用域后会自动释放。
下面上一个程序然后把他的空间结构打印出来看看。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int ga = 23; const int gb = 12; int add(int a , int b) { int sum = a + b; printf("&a = %p\n", &a); printf("&b = %p\n", &b); return sum; } int main() { int ma = 23; int *mb = malloc(4); static int mc = 443; char *ms = "it is my a test code!!"; printf("&ga = %p\n", &ga); printf("&gb = %p\n", &gb); printf("&add = %p\n", add); printf("&ma = %p\n", &ma); printf("&mb = %p\n", mb); printf("&mc = %p\n", &mc); printf("&ms = %p\n", ms); printf("pid = %d\n", getpid()); while(1) ; }
该程序运行后个变量和函数的地址对应关系:
进程空间图:
按照地址的对应关系的话就能够找到每个变量对应的存储区域。
3.关于函数
待续…
注:查看进程地址空间的方法,查看Linux下的/proc/$pid/maps文件