- linux 常用工具简介:
- tar打包器---解压缩指令:
- 常用命令:
- 可执行文件查看(代码段,数据段,bss段):
- 堆和栈的区别:
- 常见内存错误说明:
- 内存分配相关理解:
- 1.内存分配方式:
- 2.动态分配常用函数及说明:
- 2.1 malloc & free:
- 2.2 realloc:
- 2.3 calloc():
- 2.4 alloca ():
- 3 内存常用管理函数:
- 3.1 memcpy():
- 3.2 memmove():
- 3.3 memset():
- 3.4 memchr()
- 3.5 memcmp():
- 文件与文件流及相关操作函数:
- 1.文件存储及操作分类:
- 2.标准流及流主要功能:
- 3.文件流指针:
- 4.缓冲区类型及指定:
- 4.1缓冲区分类:
- 4.2 缓冲区指定函数:
- 5 ANSI C文件I/O操作:
- 5.1 fopen()打开文件:
- 5.2 关闭文件fclose() /fcloseall():
- 5.3 更新缓冲区内容fflush:
- 5.4 字符读操作:
- 5.5 字符写操作,标准流中写一个字符:
- 5.6 行读出操作:
- 5.7 行写入操作:
- 5.8 块读出操作:
- 5.9 块写入操作:
- 5.10 feof() 文件末尾检测函数:
- 5.11 ferror() 函数判断给定流是否错误:
- 5.12 clearerr() 清除错误标识位
- 5.13 ftell() 返回当前读写位置:
- 5.14 fseek() 修改当前读写位置。
- 5.15 rewind() 重置当前读写位置
《Linux 高级程序设计》
-
UNIX 操作系统于1969 年在AT&T贝尔实验室实现。收取少量费用供其它开发者使用修改。
-
加州大学伯克利分校计算机系统研究小组CSRG 借助UNIX 对操作系统研究,改进,包括撰写更好的内存管理等,组成完整的BSD-UNIX 系统向外发行。
-
Linux 由操纵系统发展而来,由Linux Torvalds 和网络黑客从0编写。是一套开源代码,但遵循GNU 的GPL.(因为不限制商家对自由软件进一步开发,因此出现ubutu, redhat 等多个linux发行版)
-
GUN 项目开发很多高质量编程工具(如emacs,gcc,g++),所有GNU软件和派生工作均使用GNU 通用公共许可证(GPL)。
-
posix 标准表示可移植操作系统接口,不局限于UNIX 。posix 提供源代码级别的C语言应用编程接口,如read/write. posix 1.0 和 posix2.0 分别定义了兼容操作系统的C语言系统接口以及工具标准。
-
库函数和系统调用:库函数完成常见功能,系统调用通常与操纵系统有关,库函数最终一般还是会调用系统函数。系统函数会从用户模式切换为内核模式,然后使用系统资源。
-
glibc 函数库:c语言并没有为常见的操作,如输入/输出,内存管理等提供内置支持。这些功能一般由标准函数库来提供。GNU 的函数库glibc 是Linxu 最重要的函数库,定义ISOC 标准所有库函数以及posix附加特色及GNU其他扩展。
-
在线文档查询: 命令行man xxx, 工具软件则是用info(m/n/p/q 等指令).
-
获取错误信息方法:当系统调用出错时会返回-1, 错误信息记载在全局errno 中。 有关errno定义在/usr/include/asm/errno.h 中。
ERERM 0 :没有操作权限 ENOENT 1:文件或目录不存在 ESRCH 3:没有此程序 EINTR 4:系统调用中断 EI0 5:I/0错误 错误打印输出函数,一般使用perror(“hxg”); 后面自动会将错误信息打印输出。也可以使用strerror 将错误打印到标准输出。
解压缩指令:
- tar -cvf filename.tar xxxfile //将xxxfile 打包成filename.tar
- tar -xvf filename.tar //解压打包文件
- tar -cjvf filename.tar.bz2 xxxfile //将xxx file 用bz2 压缩并打包
- tar -xjvf filename.tar.bz2 //强filename.tar.bz2 解压缩
- tar -czvf filename.tar.gz directory/file 将file用gzip压缩并打包
- tart -xzvf filename.tar.gz //解压一个gzip格式的Tar 文件。
- expand 如expand -t 4 hello.c 将hello.c 的制表符设置为4个空格
- grep 搜索字符串
- -i: 不区分大小写
- -I:只首次匹配
- -n: 输出前加匹配串所在行的行号
- find 查找文件
gcc -o test hello.c
$: ls test -l 查看文件test的属性
$: file test 列出ELF 格式; ELF 格式可执行文件存储时分为代码区(text),数据区(data)和未初始化数据区bss 3个部分。 也可以readelf -a test 读取test 详细的elf 信息。
- 代码区:CPU可执行的指令,通常为只读。被const声明的变量以及字符串常量在代码段中申请空间。
- 数据段:已被初始化的全局变量或已初始化的静态变量(静态全局变量和静态局部变量),或者数据常量。
- BSS 区(未初始化的数据区):未初始化的全局变量和静态变量。
- 局部变量是运行中在栈中分配。
- 管理方式不同:栈操作由系统自动管理完成,而堆工作由程序员管理控制
- 空间大小不同:系统预先设定栈顶和大小,当申请空间超出栈剩余空间时,将出现栈溢出错误。堆是向搞地质扩展,不连续的内存。
- 产生碎片不同:频繁使用malloc、free 会产生大量碎片,使得程序效率降低。
- 分配方式不同:堆由malloc 和free 分配释放,而栈动态分配有alloca() 完成且其由编译器自动申请和方式,无需手工。
- 分配效率不同: 堆分配效率较低。
- 拒绝返回局部变量地址。
- 操作系统加载某个应用程序时,分配一定大小的栈空间。避免申请过大局部变量以出现栈溢出。
- 动态内存管理常见错误:
- 申请和释放函数不一致! 使用C申请就是用C释放,使用C++申请就使用C++释放
- 申请和释放大小不一致! 申请多少就释放多少
- 释放后仍然读写! 释放后内存不应再读写。
- 静态分配:编译器在编译源代码时分配,如全局和静态变量。程序执行前分配,效率高。可直接使用变量名字操作。
- 动态分配:程序执行时调用malloc() 库函数申请。程序执行时分配,效率低。使用指向内存的指针是使用动态内存的唯一方法。
说明:
-
malloc()分配连续存储的空间,返回该空间的首地址;当剩余空间不足时,返回NULL
-
free()与malloc()配套使用,用于释放malloc分配的内存。
特点:
- malloc 分配的内存使用完需要使用free释放
- 不要使用free释放非malloc 分配的内存
- 内存首地址返回的指针不要进行加减操作再free,否则会引发问题
- 不能两次释放相同的指针
- 内存释放后,指向内存的指针应该被赋值为NULL。
说明:
- 在堆中更改已经分配的内存空间。extern void *realloc(void *ptr,size_t size);
特点:
- 当前内存段后面拥有足够内存空间则直接扩展这段内存空间,返回原指针
- 如果当前内存段后空闲字节不够,就重新寻找满足的内存块,并将目前数据copy到新位置,原始数据块释放(即释放原来指针realloc()的参数指针),返回新内存块地址。
- 如果申请失败,则返回NULL.
说明:
- 是malloc的简单包装,特点是将动态分配的内存初始化为0.
说明:
- 在栈中分配size个字节的内存空间,函数返回时自动释放掉该空间。
extern void* memcpy(void* des, const void* src,size_t n)
- 从src copy n 个字节数据到des地址。
- 类似strncpy()只是strncpy() 参数为char* 类型。
- 类似bcopy(), 只是bcopy 多用于网络编程中。
extern void* memmove(void* dest, void* src,size_t n)
- 类似memcpy ,当dest 和src 没有重合时,与memcpy相同
- 当dest与src 有重叠时,先处理再将src copy n 字节到dest.
extern void * memset(void *s, int _c, size_t _n)
- 将s开始后面n位的值设置为c,执行成功返回s首地址。
- 类似bzero()函数,bzero(s,n); 将s开始n字节设置为0
extern void* memchr(const void* _s, int _c,size_t _n)
- 在s中的前n个字节中查找c第一次出现的位置
extern int memcmp(const void* s1, void* s2, size_t _n)
- 比较s1 和 s2 前n个字节是否相同
- s1=s2 返回0, s1
s2 返回1 - 类似strncmp() 函数
文件存储分类:
- 文本文件:ASCLL文件,文本文件存储量大,速度慢。文件以EOF结束
- 二进制文件:存量小,速度快,便于存放中间结果
文件操作分类:
- 缓冲文件操作:在用户空间自动为使用的文件开辟内存缓冲区,通过一次系统调用读取较多数据到缓冲区,这样避免每次读写都要进行系统调用。(系统调用会将CPU从用户态切换至内核态,影响效率)。
- 非缓冲文件操作:最多只能在程序中开启缓存空间,每次读写都是一次系统调用。
- Linux 系统中,系统默认为每个进程打开3个文件,即每个进程默认可以操作3个流,标准输入流(/dev/stdin),标准输出流(/dev/stdout),标准错误输出流(/dev/stderr).
- 每个进程从标准输入流读数据,向标准输出流写数据,向标准错误输出流写错误信息。
- 可以通过重定向,修改输入流/输出流。
在应用编程层面,程序对流的操作实际就是对文件流指针FILE的操作。操作一个文件前通过fopen()打开一个文件,返回该文件流指针且该指针与该文件关联。该文件流指针是一个文件描述符,对应的结构体可在用户空间进行访问。
4.缓冲区类型及指定: 4.1缓冲区分类:- 全缓冲区:该缓冲区默认大小与系统定义有关,大小定义在/usr/include/libio.h。 在缓冲区满或者调用刷新函数fflush() 后才进行I.O系统调用操作。普通磁盘文件的流通常使用全缓冲区访问。
- 行缓冲区:行大小根据系统有关,通常默认128字节。当遇到换行符或缓冲区满时,行缓冲才刷新。终端使用行缓冲区古。
- 不带缓冲区:标准I/O库不对字符进行缓存。标准出错流stderr 通常是不带缓冲区的,以便错误信息能够尽快显示出来。
使 用 缓 冲 区 , 不 需 要 每 次 进 行 标 准 I / O 处 理 时 都 使 用 系 统 I / O 调 用 color{red}{使用缓冲区,不需要每次进行标准I/O处理时都使用系统I/O调用} 使用缓冲区,不需要每次进行标准I/O处理时都使用系统I/O调用
4.2 缓冲区指定函数:setbuf():
extern void setbuf(FILE* __stream,char* __buf);
- 第一个参数为要操作的流对象
- 第二个参数是指向BUFSIZ长度的缓冲区。如果buf设置为NULL,则关闭缓冲区。
- 执行成功范围0,否则返回非0
setvbuf():
extern int servbuf(FILE* __stream, char* __buf, int __modes, size_t __n);
- 第一个参数为要操作的流对象
- 第二个参数buf指向一个长度为n大小的缓冲区
- 第三个参数为缓冲区类型 ;#define _IOFBF 0 全缓冲;#define _IOLBF 1 行缓冲;#define _IonBF 2 无缓冲。
- 如果指定不带缓冲区的流,则buf和n参数都忽略;如果buf=NULL,则系统默认分配适当大小的缓存区。
extern FILE* fopen(__const char* __filename,__const char* __modes);
- 第一个参数为打开文件的绝对路径或者相对路径。
- 第二个参数为打开方式:具体如下:
- 函数执行成功则返回文件指针,如果文件打开失败则返回NULL
fclose():
extern int fclose(FILE* __stream)
- 参数为文件流指针
- 当close文件时, 操 作 系 统 会 自 动 将 缓 冲 区 的 内 容 回 写 到 文 件 color{red}{操作系统会自动将缓冲区的内容回写到文件} 操作系统会自动将缓冲区的内容回写到文件
- 成功返回0,否则返回EOF, 并设置errno 全局变量。
extern int fcloseall(void);
- 关闭所有流对象。如进程关闭时,需要关闭打开的所有流对象。
通过I/O系统调用将缓冲区内容写会磁盘中。
extern int fflush(FILE* __stream);
- 函数执行成功返回0,否则返回EOF,并设置标准错误error
extern int fgetc(FILE * __stream); //从流中读一个字符 extern int getc(FILE *__stream); //#define getc(_fp) _IO_getc(_fp)
- 每次系统调用只从流中读出一个字符。
- 成功返回读的内容,失败或文件结束则返回EOF(-1)
- feof() 检测是否督导结束
- ferror() 检测是否出错
- 比如fgetc(stdin) 从标准输入流读一个字符。标准输入读一个字符还可以使用getchar() //extern int getchar(void);
extern int fputc(int __c, FILE* __stream) //将字符c写到流stream中 extern int putc(int __c, FILE* __stream)
- 向标准输出流写一个字符可用putchar()相当于fputc(c,stdout). //extern int putchar(int __c);
- 调用成功返回内容,失败返回-1
extern char* fgets(char* __s, int __n, FILE *__stream)
- 从strean 中读取n-1个字符存放到s中。
- 成功返回s,失败(到文件尾部或出错)则返回NULL,
extern int fputs(__const char* __s, FILE* __stream) extern int puts(__const char* __s) //输出流到标准输出设备中
- fputs 将s指向的以空字符结尾的字符串写入stream中
- puts()将s指向的以空字符结尾的字符串写入标准输出
- 成功返回非负,失败返回-1
extern size_t fread(void* __ptr,size_t __size, size_t __n, FILE* __stream)
- 从stream 中读取n个大小为size的对象,存放在ptr所指的内存空间。
- 返回实际读取到对象的个数,如果返回值
extern size_t fwrite(__const void* __ptr, size_t __size, size_t __n, FILE *__S);
- 从ptr 中读取n个大小为size的对象写入s指向的stream中。
- 执行成功,函数返回实际写入的对象个数。
extern int feof(FILE* __stream)
- ASCLL文件可以直接根据返回值是否=EOF判断
- 二进制文件需要使用该函数,返回1表示读到文件结束,否则返回0
extern int ferror(FILE* stream)
- 没有错误将返回0
- 否则返回错误符
extern void clearerr(FILE* __stream)
- feof 或ferror 执行后,如果出现错误,将设置错误标识符,执行错误处理后需要清除错误标识符。
extern long int ftell(FILE* __stream)
- 成功返回流的当前读写位置距离文件开始的字节数
- 失败返回-1
extern int fseek(FILE* __stream, long int __off, int__whence)
- 第一个参数为stream 流
- 第二个参数为基于修改基础的偏移量
- 第三个参数为修改位置的基准;SEEK_SET :文件开始;SEEK_CUR:当前位置;SEEK_END:文件结束位置
extern void rewind(FILE * __stream)
将读写指针移动到文件开头
案例:
FILE* fp_src;
fp_src=fopen("/mytest.cpp",r+);
if(fp_src==NULL)
perror("errorn");
do{
num=fread(buf, 1, 128, fp_src); //读取128字节到buf中
if(feof(fp_src)==1)
break;
}while(1)
fclose(fp_src);



