0%

Unix-Linux编程实践教程-章节1笔记

more

more的三种用法

1
2
3
more filename      //分页显示文件内容
command | more //将command命令的输出分页显示
more < filename //more从标准输入中获取要分页显示的内容,而标准输入被从重定向到filename
  • enter显示下一行,space显示下一页,q退出
  • 管道命令|将command的输出重定向到more的输入

例如命令ls /bin | more,ls命令的标准输出重定向到more的标准输入,如果还是使用getchar()来读取用户的输入,那么就会从ls的输出中读取,这显然不行,所以需要其他方式

/dev/tty

通过在more命令中打开/dev/tty文件进行读取的方式,使得more可以从其他途径中获取到用户输入

  • 键盘和显示器的设备描述文件
  • 向这个文件写相当于显示在用户的屏幕上,读相当于从键盘获得用户的输入

C函数

gets

1
2
3
#include <stdio.h>

char *gets(char *s);
  • 将读取到内容保存在s中,遇到换行符、文件结尾时读取结束,不会检查输入会溢出s的大小
  • 该函数于C11已经废弃
  • 返回值:读取正确返回s,发生错误返回NULL,溢出则什么可能都会发生

fgets

1
2
3
4
5
6
7
8
#include <stdio.h>

int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int getc(FILE *stream);
int getchar(void);
int ungetc(int c, FILE *stream);

  • fgets:读取到size-1个字符(最后一个位置会填上\0),遇到换行符,文件结尾时结束
  • 返回值:
    • 对于fgets如果返回s表示读取成功,如果返回NULL表示读取错误或者什么都没有读取到
    • 对于其他函数(除了ungetc),返回读取到的字符转化为int的值,返回EOF表示错误或者读取到了文件结尾

fputs

1
int fputs(const char *str, FILE *stream);
  • 返回值:该函数返回一个非负值,如果发生错误则返回 EOF(-1)。

fgetc

1
int fgetc(FILE *stream);
  • 功能是从文件指针指定的文件中读入一个字符,该字符的ASCII值作为函数的返回值。
  • 若返回值为EOF,说明文件结束。如果发生错误也返回 EOF(-1)

perror

  • 使用perror()函数,它可以自己查找错误代码,并在标准错误输出中显示相应的错误信息
  • 参数:string是同时显示的描述信息,例如对于文件操作的代码,可以把文件名作为描述信息传进去
1
2
#include <stdio.h>
void perror(const char *s);

strtoul

1
2
#include <stdlib.h>
unsigned long int strtoul(const char *nptr, char **endptr, int base);
  • 该函数尝试将字符串转换为一个无符号长整型

  • 参数:

    • nptr:待转换的字符串
    • endptr:如果传入指针不为NULL,则返回nptr中首个不为合法数字的字符的地址(使用指针的指针就是为了能够修改指针的内容);当遇到首个不合法字符时,转换过程停止。
    • base:应该以何种进制来解释字符串中的数字,该值可以传入2~36,或者特殊值0;如果传入0则该函数会根据字符串首部来确定进制:
      • 如果 nptr 以 “0x” 或 “0X” 开头,则基数为 16。
      • 如果 nptr 以 “0” 开头,则基数为 8。
      • 否则,基数为 10。
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
    const char *str = "12345abcd"; // 输入字符串
    char *end;
    unsigned long int value;
    value = strtoul(str, &end, 10); // 转换为十进制的无符号长整型
    printf("转换结果: %lu\n", value);
    printf("未转换的部分: %s\n", end);
    return 0;
    }

    输出:

    1
    2
    转换结果: 12345
    未转换的部分: abcd

C语言知识复习

  • sizeof(string):会计入’\0’

声明字符串的两种方式

1
2
char *str = "hello wrold";
char str[] = "hello wrold";
  • char *str里的str是指针变量,指向一个字符串常量
    • sizeof(str):返回的是指针变量的大小,而不是字符串的长度
    • str[0] = 'H:会报Segment fault错误,常量字符串不可修改
    • str = "Hello":指针可以修改指向不同的常量字符串
  • char str[]里str是地址常量,str的值是str[]的地址,它声明了一个字符数组
    • sizeof(str):返回字符串的大小,包括’\0’

C语言的内存分配方式

内存分配可分为三种:静态存储区、栈区、堆区

1、静态存储区:该内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,它主要存放静态数据、全局数据和常量
2、栈区:它的用途是完成函数的调用。在执行函数时,函数内局部变量及函数参数的存储单元在栈上创建,函数调用结束时这些存储单元自动被释放。
3、堆区:程序在运行时使用库函数为变量申请内存,在变量使用结束后再调用库函数释放内存。动态内存的生存期是由我们决定的,如果我们不释放内存,就会导致内存泄漏。

linux系统调用

read

1
2
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
  • 返回值:成功则返回读取数量,遇到错误返回-1

open

  • open()已经逐渐取代了creat()的使用
1
2
3
#include <fcntl.h>
#include <sys/types.h>
int open(const char *pathname, int flags, mode_t mode);
  • 参数:

  • flags:

    • O_RDONLY, O_WRONLY, O_RDWR,分别对应只读,只写,读写三种;这三个参数应指定其中一个,然后或上可选参数:
    • O_CREAT若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限
    • O_EXCL如果同时指定了O_CREAT而文件已经存在,则出错
    • O_APPEND每次写时都加到文件的尾端。(写文件在文件末尾不会覆盖原先内容)
    • O_TRUNC属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。(如果文件里面有东西直接删然后写)
  • mode: 一定是在flags中使用了O_CREAT标志,mode表示待创建的文件的访问权限

  • 返回值:成功则返回文件描述符,遇到错误返回-1

  • 打开文件可能出错的原因多种多样,具体请查看文档

close

1
2
#include <unistd.h>
int close(int fd);
  • 返回值:0表示成功关闭,-1表示出现错误

ctime

1
2
#include <time.h>
char *ctime(const time_t *timep);
  • 返回值:格式为"Wed Jun 30 21:49:08 1993\n"的字符串
  • time_tlong int类型
  • utmp文件中的ut->time表示用户从登录时间到初始时间所经过的秒数

creat

1
2
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
  • 参数:
    • mode:访问模式,传入三个用户组的权限对于该文件的权限(mode_t应该是unsigned int类型)
  • 返回值:成功返回文件描述符,失败返回-1
  • 没有则创建文件,如果文件存在则它的内容会被清空。

write

1
2
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
  • 返回值:成功则返回写入的字节数,失败则返回-1
  • 为什么写入字节数会少于指定数量:
    • 系统对文件的最大长度有限制,或者磁盘空间不足
    • 因此有必要校验是否完全写入

lseek()函数

1
2
3
#include <sys/type.h>
#include <unistd.h>
off_t oldpos = lseek(int fd , off_t dist , int base)
  • 参数:
    • dist:移动的距离
    • base:SEEK_SET -> 文件开始SEEK_CUR -> 当前位置SEEK_END -> 文件结尾
  • 返回值:返回指针变化前的位置,返回-1表示遇到错误

stat()函数

该函数返回关于一个文件的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);

// 文件属性
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */ 索引编号
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */

/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */

struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */

#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

//检查文件类型
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))

#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) //目录
#define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR) //字符特殊设备
#define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK) //块特殊设备
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG) //普通文件
  • 返回值:如果成功返回0,否则返回-1,并且error会设置为相应的错误类型

ioctl()

用来操作底层设备文件的参数的系统调用。ioctl 的作用非常强大、灵活。不同的驱动程序内部会实现不同的 ioctl,应用可以使用各种 ioctl 跟驱动程序交互:可以传数据给驱动程序,也可以从驱动程序中读出数据。

1
2
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
  • 参数:
    • fd 表示文件描述符;
    • request 表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据;
    • … 表示可变参数 arg,根据 request 命令,设备驱动程序返回输出的数据
  • 返回值:
    • 通常成功返回0,失败将返回-1

mmap()

1
2
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
  • 参数:
    • addr:表示指定映射的內存起始地址,通常设为 NULL 表示让系统自动选定地址,并在成功映射后返回该地址;
    • length:表示将文件中多大的内容映射到内存中;
    • prot:表示映射区域的保护方式,可以为以下 4 种方式的组合:
      • PROT_EXEC 映射区域可被执行
      • PROT_READ 映射区域可被读出
      • PROT_WRITE 映射区域可被写入
      • PROT_NONE 映射区域不能存取
    • flags:表示影响映射区域的不同特性,常用的有以下两种:
      • MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。
      • MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回原来的文件内容中
    • fd:被映射的文件描述符
    • offset:从文件的offset偏移位置开始映射
  • 返回值:
    • 若成功映射,将返回指向映射的区域的指针,失败将返回-1