1. 其他知识点
1.1. man 手册
1.2. ctags追踪
ctags索引:
- vi -t 要查找的内容,(查找宏,数据类型等)
输入前面序号,回车 - 继续追踪
将光标定位到要追踪的内容上,ctrl+]
回退:ctrl+t
1.3. exec函数族 在一个进程里 运行其他进程
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
代码:在一个进程里 运行其他进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define SYSTEM_FLAG 1
#define EXEC_FLAG_1 1
#define EXEC_FLAG_2 1
/* 常用的:在一个进程里面,运行其他进程 */
int main(int argc, char *argv[])
{
#if SYSTEM_FLAG //system 族
system("ls -l");
#endif
#if EXEC_FLAG_1 //exec 族
/* 进程所在目录、进程文件名字、参数、用NULL结尾 */
execl("/bin/ls", "ls", "-l", NULL);
#endif
#if EXEC_FLAG_2 //exec 族
/* 参数为可变参 */
execl("./", "./a.out", NULL);
#endif
}
1.4. 区别:线程互斥信号量、进程早期信号通知、进程IPC V信号灯集
重点关注,不要混淆
1.4.1. 进程早期信号通知
指的是:系统进程和应用进程等,进程之间通知的信号。
1.4.2. 线程互斥信号量
主要用于PV操作的,单个信号量个体
1.4.3. 进程IPC V信号灯集
在 线程互斥信号量
的基础上升级,能够以集合的形式,操作多个单体信号量
1.5. 信号灯集、消息队列,返回id为0怎么处理?(共享内存无该问题)
很多种原因,暂时不会解决。
不能总是删了重新运行,这不是个办法
2. 标准IO
2.1. 练习:通过fgetc与fputc函数实现cat功能.
/* 练习:通过fgetc与fputc函数实现cat功能.
注意:fgetc官方 返回值为int,不用char
字符补码保存;若变量ch 为char类型读到字符0xFF与EOF(-1)比较时相等,误判为已经读到文件末尾
*/
#include <stdio.h>
int main(int argc, char *argv[])
{
// argv[0]是文件名字,1是后续第一个参数
FILE *fp = fopen(argv[1], "r");
if (NULL == fp)
{
perror("fopen err");
return -1;
}
// 不到EOF 且同时 不读出错,则 循环 读取 打印 流
int ch;
while (((ch = fgetc(fp)) != EOF) && !ferror(fp))
fputc(ch, stdout);
putchar(10);
// 关闭文件流
fclose(fp);
}
2.2. 用标准IO实现cp功能
diff 文件名1 文件名2 :对比文件1 与文件2是否有不相同的地方
#include <stdio.h>
int main(int argc, char *argv[])
{
char buf[32];
// 打开 源文件(被复制的文件)
FILE *src = fopen(argv[1], "r");
if (NULL == src)
{
perror("src err");
return -1;
}
// 打开 目标文件(复制后的文件)
FILE *dest = fopen(argv[2], "w");
if (NULL == dest)
{
perror("dest err");
return -1;
}
// 循环 读源文件 写入 目标文件
while (fgets(buf, sizeof(buf), src) != NULL)
fputs(buf, dest);
// 关闭 流
fclose(src);
fclose(dest);
}
2.3. 实现“head -n 文件名”命令的功能 (显示文件前n行)
例:head -3 test.c -> ./a.out -3 test.c
atoi : "1234" -- 1234
atoi:将字符串转化为整型
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buf[32] = {0};
if (argc != 3)
{
perror("err input");
return -1;
}
FILE *fp = fopen(argv[2], "r");
if (fp == NULL)
{
perror("open err");
return -1;
}
// 读取n行,参数为字符串转换为整形
// int num = -arot(argv[1]);
// int num = -1 * arot(argv[1]);
int num = atoi(argv[1] + 1); //+1为从-的身后数字开始
// 循环读取 并输出
// fgets会在读到如下情况停止:\n,文件结束
// 读到末尾会返回NULL,所以可 不用判断 num等于0,就已经结束了
while (fgets(buf, 32, fp) != NULL)
{
// 字符长度 比 下标大1
if (buf[(strlen(buf) - 1)] == '\n')
num--; //几个\n就是输出了几行
fputs(buf, stdout);
memset(buf, 0, sizeof(buf) / sizeof(*buf));
// 还有几行要打印
if (num == 0)
break;
}
fclose(fp);
return 0;
}
2.4. 编程读写一个文件test.txt,每隔1秒向文件中写入一行数据
类似这样:
1, 2007-7-30 15:16:42
2, 2007-7-30 15:16:43
该程序应该无限循环,直到按Ctrl+C中断程序。
再次启动程序写文件时可以追加到原文件之后,并且序号能够接续上次的序号,比如:
3, 2007-7-30 15:16:42
4, 2007-7-30 15:16:43
5, 2007-7-30 15:19:02
6, 2007-7-30 15:19:03
7, 2007-7-30 15:19:04
分析:
1. 打开文件fopen,以a+的形式打开,循环往文件写内容
2. 每隔1s写入一行,sleep(1);
3. 计算文件行数,wc -l
4. 计算当前时间,转换成年月日、时分秒,time,localtime
5.字符串拼接函数:strcpy/strcat(dest, src)、sprintf、fprintf
6.全缓冲
//time:计算时间,获取秒数
//localtime:将时间秒数转化成当地年月日时分秒
//fprintf:()
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// 追加打开 或 创建文件
FILE *fp = fopen("./test.txt", "a+");
if (NULL == fp)
{
perror("err fopen");
return -1;
}
// 计算文件行数
char buf[32] = {0};
int line = 0;
while (fgets(buf, sizeof(buf), fp) != NULL)
if (buf[strlen(buf) - 1] == '\n')
line++;
// 循环向文件中写
while (1)
{
// 获取 当前时间
time_t t = time(NULL);
// 转化 时间秒数 为年月日十分秒
struct tm *tm = localtime(&t);
// 向文件写入,属于文件缓冲,需要强制刷新,写入进去
fprintf(fp, "%d,%d-%d-%d %d:%d:%d\n",
++line,
tm->tm_year + 1900, //在1900基础开始,需要+1900
tm->tm_mon + 1, //月份从0开始,需要+1
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
// 强制刷新
fflush(fp);
sleep(1);
}
// 关闭 文件流
fclose(fp);
}
3. 文件IO
3.1. 用文件IO实现cp功能。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char buf[32] = {0};
ssize_t s = 0;
// 打开目标文件和源文件
int src = open(argv[1], O_RDONLY);
int dest = open(argv[2], O_TRUNC | O_WRONLY | O_CREAT, 0666);
if (dest < 0 || src < 0)
{
perror("open err");
return -1;
}
// 循环读写
while ((s = read(src, buf, sizeof(buf))) != 0)
{
// 读多少,写多少
write(dest, buf, s);
}
close(src);
close(dest);
}
4. 进程
4.1. cp拷贝 父子进程 文件IO
要求:文件IO cp src dest
通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件的一半开始拷贝,子进程从文件的一半到文件末尾。
提示:
- 长度获取:lseek() 400-->200
- 定位到一半lseek
- buf[32] 200-32-32 read
- fork之前打开文件还是fork之后打开文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#define N 32
int main(int argc, char *argv[])
{
// 打开 源文件 目标文件
int src = open(argv[1], O_RDONLY);
int dest = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0