C语言扫盲及深化学习
c语言特点:
(1)效率高
(2)控制性强
(3)硬件亲和性好
(4)可移植性高
一、关于注释
c语言中注释不能嵌套,因此注释代码时一定要注意源代码中是否已经存在注释。要从逻辑上删除一段代码,利用预编译指令更加安全有效,其格式为:
#if 0
statment;
#endif
二、关于函数参数
如果函数参数带有const,则表示函数将不会改变调用者传递的参数。
三、关于传址和传值
在c语言中,标量和常量是按值传递,而数组是传址调用,传值会有临时拷贝,被调函数内部修改该参数对调用函数来说是无效的。所有传递给函数的参数都是按值传递的,但是数组是按引用传递。
四、关于c语言的编译链接过程
源码 -> 编译(预处理 + 解析语义 .o文件,即目标代码)-> 链接(目标文件 + 库文件) -> 可执行文件
可执行文件的运行,会绑定一个启动程序,用于处理一些其他事项。
五、关于链接属性
链接属性的作用:标识符的链接属性决定如何处理在不同文件中出现的标识符,标识符的作用域与连接属性有关。
简单的讲,当有多个源文件时,链接属性可以更好的处理所有文件之中的标识符变量,尤其是多个文件中出现的同一个标识符,使程序结构更明晰。
链接属性的类型(以文件为维度):external->文件外部可访问;internal -> 只能在文件内部访问
链接属性对应的关键字:extern 和static,extern表示可访问其他文件中相同的标识符(包括函数和变量),比如可以在file1中定义int a;然后在file2中声明 extern int a;则表示的是file2中的变量a是引用file1中的变量a,也就是说这两个文件中的a是同一个变量。
一般的,全局变量和函数名的默认链接属性为external,而局部变量默认为internal
可以用extern和static关键字修改默认链接属性,如全局变量 static int a;表示a的连接属性为文件内部;而static int function()表示函数function的连接属性为文件内部,即只能在该文件中调用该函数;而对于局部变量extern int b,则表示b为其他文件中定义的变量,即其连接属性为external。
注意:static除了以上表示链接属性的用法之外,还有一种用法,就是将static用于局部变量,对于局部变量sttaic int c来说,其不是改变c的链接属性,而是改变c的存储位置,使得c不再存储在进程的栈空间中,而是编译时将局部变量c存储在进程的.data段(初始化的静态数据区),因此,在该进程中当下一次访问变量c时,c的值为最近修改后的值。这就是static常用的三大用法,即修饰全局变量、修饰函数和修饰局部变量。简单讲,static的主要作用就是定位。
六、const和static关键字作用总结
c语言中static三大作用:修饰全局变量、修饰函数和修饰局部变量。当static修饰全局变量和函数时,表示的是链接属性的特征,表示该全局变量或者是函数的链接属性为internal,只有在其所在的文件内可以被访问与调用;而当static修饰局部变量时,不再表示链接属性的特征,而是表示该局部变量的存储位置在.data段(初始化的静态数据区:因为静态局部变量默认情况下会被编译器初始化为0)。
c语言中const常常存在于三种形式:const常量、const与指针和const与形参。const常量就是在一般变量前面加上const修饰,表示该变量不可更改,因此叫做const常量,即给字面值一个名字;const与形参表示的是在函数的声明中将参数用const来修饰,const修饰的形参表示在函数内部该参数不可被更改,这样既能表明编程者的意图,也能防止错误;而const与指针的情况比较复杂,因为涉及到指针和其所指代的内容两个因素,因此,const修饰的是指针还是其所指代的内容,是一个特别容易混淆的点。如下所示作以区分:
(1)int const *pci
写成如上形式,const修饰的是什么呢?有一个简单的记忆法(首先要求将星号跟随变量名作为一个书写习惯,如上述的代码不应写成 int* const pci
,虽然也没错,但是习惯问题),因此const修饰的是*pci,而*pci的语义是指针所指代的内容,所以说该种写法表示指针可以修改,但是其所指代的内容不可更改。
(2)int * const pci
显而易见,该种写法const修饰的是pci指针,所以其语义是pci是一个常量指针,指针的值(即所指地址)不可修改;而指针所指代的内容是普通变量,可以修改。
(3)int const * const pci
该种写法就容易理解了,即表示的是指针和其所指代的内容都不可更改。
对于以上const的技法,有一个口诀:即看*与const的相对位置,右定值,左定向(左右是指*的位置)
七、关于右值和左值
在c语言中,所谓左值指的是存储位置,而右值就是指值。例如:
a = b + 5;
其中, a是个左值,因为他标识了一个可以存储结果值的地点(相当于门牌号),而b + 5 是一个右值,他是一个值(相当于屋内的东西)。
结论:凡是可以清晰表示地址概念的都可以作为左值,凡是可以清晰表示值的概念的,都可以作为右值。
八、可变参数列表实现
c语言可通过stdarg.h中定义的方法实现可变参数列表,这个头文件声明了一个va_list的类型和三个宏操作:
(1)va_start:初始化va_list,将va_list变量设置为指向可变参数部分的第一个参数。
(2)va_arg:访问指定参数的值,并且使指针指向下一个可变参数。
(3)va_end:访问结束。在访问最后一个参数后,调用该函数,可变参数访问结束。
(4)va_list:用于访问参数列表的未确定部分
九、数组与指针的区别
数组名和指针都具有指针值,都可以进行间接访问和数组下标访问,但是,声明数组和指针时,其内存状态存在很大的不同,这一点需要重点理解。比如下面的例子:
int a[5]
int *b
声明a时,编译器首先为数组a开辟5个int大小的内存空间,然后创建数组名a为常量,并将其指向这段空间的起始内存地址;而声明指针b时,则只是为指针变量本身开辟一个内存空间,其值可能不会被初始化,不会指向任何有意义的地址空间;但是b++合法,b不合法,而a++不合法(a是常量),a合法。
十、指向数组的指针
int matrix[3][10];
int (*p)[10] = matrix;
p是一个指针,是一个指向拥有10个整型元素的数组的指针。
对于多维数组做函数参数的情况来讲,要特别注意其函数原型的声明形式。
func(int (*p)[10]);
func(int matrix[][10]);
以上两个参数的语义是一样的,都是指:指向包含10个整型元素的数组的指针,其中,一维以后的数组长度在形参中不可省略;而不能将二维数组的形参声明为func(int **p)
,该参数的语义是声明一个指向整型指针的指针,与指向数组的指针不是一个概念,要特别注意。
十一、字符串操作函数注意事项(string.h)
(1)计算字符串长度函数--strlen
strlen函数的返回值为size_t,其在stddef.h定义为无符号整数,因此使用时可能会出现意想不到的结果,比如无符号整数和0比较,将不会得到正确的结果,因此在使用其返回值时要将其强制转换为int类型。
(2)不受限制的字符串函数--strcpy\strcat\strcmp
这些函数在使用时不会自动检查目标数组的长度,因此程序员在使用时必须时刻牢记检查目标数组的长度,以免越界产生不可预想的错误。
(3)长度受限的字符串函数--strncpy\strncat\strncmp
strncpy:若长度小于dst数组长度,剩余的自动补NUL字符;若长度大于或等于dst长度,此时结果不会以NUL字符结尾。
strncat:该函数总是在结果字符串后面添加一个NUL字符。
(4)字符串分割函数--strtok
strtok可以将一个字符数组根据不同的分隔符分割成不同的字符子串,第一个参数为NULL时,表示要查找下一个分割符。但是有一点需要注意,strtok会修改原来的字符数组。
十二、内存操作函数
内存操作函数对应于字符串操作函数,只是内存操作函数不对NUL字符进行识别。
主要包括:memcpy、memmove、memcmp、memchr、memset
十三、链表
双链表的优势:
(1)可以以任何方向或忽前忽后的遍历链表
(2)允许从任何一端开始遍历
十四、字符串数组的实现
在c语言中,字符串数组的存储实现只有两种方式:
(1)字符指针数组,即char buffer[10] = {"123","abc",...},该种方式一般只用于存储已知的常量字符串,不用于程序运行时赋值的情况。
(2)字符型二维数组,即char[][10],该方式可用于运行时字符串的赋值,注意:可以使用char (p)[10]指针按行访问二维数组,效果就是用指针p来分别访问每个字符串。
十五、关于指针的高级声明
(1)int f; //一个整型变量
(2)int *f; //一个指向整型变量的指针
(3)int *f,g; //f是指针,g是普通变量
(4)int f(); //函数声明,返回值为int
(5) int *f(); //函数声明,返回值为int型指针
(6)int (*f)(); //函数指针,指向函数调用起始点在内存中的位置
(7) int* (*f)(); //函数指针,函数返回值为int*
(8)int f[]; //数组声明
(9)int *f[]; //指针数组声明
(10)int f()[]; //非法声明,因为函数只能返回标量,不能返回数组
(11)int f[](); //非法声明,函数数组非法,因为函数代码长度不一,不能存于数组中
(12)int (*f[])(); //函数指针数组
(13)int *(*f[])(); //函数指针数组,函数返回值为int*类型
(14)int (*f)(int, float); //ANSI C标准中的函数指针声明,加入参数使声明更加明确
(15)int *(*g[])(int, float); //函数指针数组
注意:函数指针在使用时,一定要先声明函数原型,然后将函数指针初始化(使其指向一个具体函数),之后便可以向函数名一样使用该函数指针。
十六、怎样理解解引用符号*
解引用,其实就是解除引用,关于它的类型,可以根据声明一步步上推。例如:
对于char a; 解引用 a的类型就是char;
对于char b;解引用 b的类型就是char ,也就是一个字符串,而 b的类型则为char,是一个字符。
十七、字符串常量的进阶理解
实质上,字符串常量出现在表达式中的时候,实际上是一个char型指针。比如:
(1)"xyz" + 1 => y
(2) "xyz"[2] => z
(3) "0123456789ABCDEF"[value % 16] => 二进制转换为字符,并以16进制打印
十八、预处理指令
理解一个概念:什么是宏?允许把参数替换到文本中,这种实现通常称为宏或定义宏。
(1)#define:两种形式
a. #define name stuff:stuff可以是任何文本,不局限于整型常量
b. #define name(parameter-list) stuff: 宏
(2)宏和函数的优劣比较
a. 函数的调用和返回需要一定的开销(函数调用栈),而宏只是替换,没有函数栈的变化
b. 宏的参数没有类型,所以宏定义的表达式操作可以针对任何满足该操作的类型,而函数必须指明参数类型,即宏是与类型无关的。如下例子:
#define MAX(a,b) (a) > (b) ? (a) : (b) //可以用于任何满足>符号比较的类型值
c.宏参数可以传递类型,而函数不可以。
#define MALLOC(n, type) \ ((type *)malloc((n) * sizeof(type)))
该宏的调用:MALLOC(5, int);
注意:宏后面不要有分号。
由上可知,宏就是原原本本的文本替换,在替换时,一定要把所有的参数都带入替换,避免出现带副作用的宏参数,导致不易察觉的错误出现。
(3)#undef:用于移除一个已经存在的宏定义
(4)条件编译指令
#if constant-expression statements #elif constant-expression statements #else statements #endif
如果constant-expression为非零值,则statements语句被编译,否则被忽略。
(5)条件编译的一大用处是解决多重包含的问题(一个文件被多次包含在一个源文件中),使用方法如下(在头文件中使用):
#ifndef _HEADERNAME_H #define _HEADERNAME_H 1 /*all stuff */ #endif
(6)其他预编译指令:#error、#line、#progma
十九、c语言中的I/O
(1)流的分类:
a.文本流:用于处理文本,一般会对流数据进行格式化处理,以满足文本的处理要求,如在行末添加换行符等。
b.二进制流:不对流数据进行任何改变,保持其在程序或者是在设备/文本中的原本形式,适用于非文本处理。
(2)I/O函数处理数据的三种基本形式:单个字符、文本行、二进制数据,对应的函数/函数族如下所示;
a.单个字符:getchar/putchar
b.文本行:gets/puts(未格式化输入输出)、scanf/printf(格式化输入输出)
c.二进制数据:fread/fwrite
C语言扫盲及深化学习的更多相关文章
- C语言扫盲篇
C语言扫盲篇 作者:尹正杰 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接. 一.什么是C语言 C 语言是一种通用的高级语言,最初是由 ...
- C语言结构体的学习,以及gdb的调式
#include <stdio.h> #include <string.h> #define format "%d\n%s\n%f\n%f\n%f\n" t ...
- 【机器学习与R语言】5-规则学习算法
目录 1.分类规则原理 1.1 1R单规则算法 1.2 RIPPER算法 2. 规则学习应用示例 1)收集数据 2)探索和准备数据 3)训练数据 4)评估性能 5)提高性能 6)选择决策树中的分类规则 ...
- 【机器学习与R语言】3-概率学习朴素贝叶斯(NB)
目录 1.理解朴素贝叶斯 1)基本概念 2)朴素贝叶斯算法 2.朴素贝斯分类应用 1)收集数据 2)探索和准备数据 3)训练模型 4)评估模型性能 5)提升模型性能 1.理解朴素贝叶斯 1)基本概念 ...
- 【机器学习与R语言】1-机器学习简介
目录 1.基本概念 2.选择机器学习算法 3.使用R进行机器学习 1.基本概念 机器学习:发明算法将数据转化为智能行为 数据挖掘 VS 机器学习:前者侧重寻找有价值的信息,后者侧重执行已知的任务.后者 ...
- Swift - 语言指南,来自github学习
@SwiftLanguage 更新于 2016-6-6,更新内容详见 Issue 55.往期更新回顾详见<收录周报> 这份指南汇集了 Swift 语言主流学习资源,并以开发者的视角整理编排 ...
- Go语言并发与并行学习笔记(一)
转:http://blog.csdn.net/kjfcpua/article/details/18265441 如果不是我对真正并行的线程的追求,就不会认识到Go有多么的迷人. Go语言从语言层面上就 ...
- 《C语言深度剖析》学习笔记----C语言中的符号
本节主要讲C语言中的各种符号,包括注释符.单引号双信号以及逻辑运算符等. 一.注释符 注释符号和注释在程序的预编译期就已经被解决了,在预编译期间,编译器会将注释符号和注释符号之间的部分简单的替换成为空 ...
- C语言:SQLITE3的学习
Sqlite基础学习 一.sqlite的概念 SQLite是一款轻型数据库,是遵守ACID的关系型数据库管理系统,由C语言开发设计.Sqlite的设计目标着眼于嵌入式领域,所以具有占用系统资源低和处理 ...
随机推荐
- liunx 修改ssh 端口22
vim /etc/ssh/sshd_config 找到Port 22 添加 Port 5002 重启sshd /bin/systemctl restart sshd.service 防火墙释放5 ...
- vue-i18n国际化在data中切换不起作用
vue-i18n是一个针对于vue的国际化插件,使用非常简单,具体使用方式看我细细道来. 实现方式 1. 下载包 npm install vue-i18n 2. 配置 在main.js文件中加入如下配 ...
- ansible的lookup
lookup路径: /usr/lib/python2.7/site-packages/ansible/plugins/lookup 所有的lookup插件列表cartesian.py dnstxt.p ...
- [转] vue自定义组件(通过Vue.use()来使用)即install的使用
在vue项目中,我们可以自定义组件,像element-ui一样使用Vue.use()方法来使用,具体实现方法: 1.首先新建一个Cmponent.vue文件 // Cmponent.vue<te ...
- docker 中打包部署Springboot项目
1.安装jdk yum -y install java-1.8.0-openjdk* 2.安装并启动mysql mysql高版本驱动变了,最后还是安装5.6 docker pull mysql:5.6 ...
- js-事件以及window操作
属性 当以下情况发生时,出现此事件 onblur 元素失去焦点 onchange 用户改变域的内容 onclick 鼠标点击某个对象 ondblclick 鼠标双击某个对象 onfocus 元素获得焦 ...
- 通用JDBC-demo
1.JDBC 的工具包(utils):包含获取数据库连接, 关闭数据库资源等方法 JDBCTools_pro.java package com.app.utils; import java.beans ...
- AtCoder Grand Contest 027 (AGC017) D - Modulo Matrix 构造
原文链接https://www.cnblogs.com/zhouzhendong/p/AGC027C.html 题解 首先我们假装 max mod min = 1 然后对着这个构造. 将各自黑白染色, ...
- POJ 1515 Street Directions (边双连通)
<题目链接> 题目大意: 有m条无向边,现在把一些边改成有向边,使得所有的点还可以互相到达.输出改变后的图的所有边(无向边当成双向的有向边输出). 解题分析: 因为修改边后,所有点仍然需要 ...
- Linux中Buffer和Cache的区别
1. Cache:缓存区,是高速缓存,是位于CPU和主内存之间的容量较小但速度很快的存储器,因为CPU的速度远远高于主内存的速度,CPU从内存中读取数据需等待很长的时间,而 Cache保存着CPU刚 ...