先买本LINUX入门书开始看吧,至少要了解一些常用的命令和用VI编辑器写脚本。推荐鸟哥的私房菜,比较不错的一本LINUX入门书,然后开始学习C语言,至于如何学习C语言,呵呵,无非就是看书,看视频,自己写程序,然后不动再看书,看视频,自己写程序,当然,遇到问题可以GOOGLE,网络,实在找不到答案可以去一些LINUX的专业论坛提问
2. Linux C语言编程题
把子进程里的close删掉,父子进程是共享fd的,子进程删了,父进程怎么用
3. 求助一道linux C语言编程题
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#define maxsize 20
int main(int argc,char *argv[])
{
int m,n,fd1,fd2;
char s[maxsize];
if(argc==4&&(*++argv)[0]=='-'&&*++*argv=='r'&&*++*argv=='i')
if((fd1=open(*++argv,O_RDONLY))>0&&(fd2=open(*++argv,O_WRONLY))>0)
while((n=read(fd1,s,maxsize))>0)
if(write(fd2,s,n)==n&&lseek(fd2,0,SEEK_CUR)!=-1);
else
printf("write error");
else
printf("open error");
if(n<0)
printf("read error");
return 0;
}
呵呵,利用空余时间,我只能按字面意思编程(你是从哪弄的啊)
不懂的可以发信息^_^
4. 在Linux下用C语言编程
4。守护进程的创建
如果你在DOS时代编写过程序,那么你也许知道在DOS下为了编写一个常驻内存的程序我们要编写多少代码了.相反如果在Linux下编写一个"常驻内存"的程序却是很容易的.我们只要几行代码就可以做到. 实际上由于Linux是多任务操作系统,我们就是不编写代码也可以把一个程序放到后台去执行的.我们只要在命令后面加上&符号SHELL就会把我们的程序放到后台去运行的. 这里我们"开发"一个后台检查邮件的程序.这个程序每个一个指定的时间回去检查我们的邮箱,如果发现我们有邮件了,会不断的报警(通过机箱上的小喇叭来发出声音). 后面有这个函数的加强版本加强版本
后台进程的创建思想: 首先父进程创建一个子进程.然后子进程杀死父进程(是不是很无情?). 信号处理所有的工作由子进程来处理.
#include
#include
#include
#include
#include
#include
#include
/* Linux 的默任个人的邮箱地址是 /var/spool/mail/用户的登录名 */
#define MAIL "/var/spool/mail/hoyt"
/* 睡眠10秒钟 */
#define SLEEP_TIME 10
main(void)
{
pid_t child;
if((child=fork())==-1)
{
printf("Fork Error:%s\n",strerror(errno));
exit(1);
}
else if(child>0)
while(1);
if(kill(getppid(),SIGTERM)==-1)
{
printf("Kill Parent Error:%s\n",strerror(errno));
exit(1);
}
{
int mailfd;
while(1)
{
if((mailfd=open(MAIL,O_RDONLY))!=-1)
{
fprintf(stderr,"%s","\007");
close(mailfd);
}
sleep(SLEEP_TIME);
}
}
}
你可以在默认的路径下创建你的邮箱文件,然后测试一下这个程序.当然这个程序还有很多地方要改善的.我们后面会对这个小程序改善的,再看我的改善之前你可以尝试自己改善一下.比如让用户指定邮相的路径和睡眠时间等等.相信自己可以做到的.动手吧,勇敢的探险者.
好了进程一节的内容我们就先学到这里了.进程是一个非常重要的概念,许多的程序都会用子进程.创建一个子进程是每一个程序员的基本要求!
5. linux c编程
/*
Name: list.c
Author: guozan _SCS_BUPT
Mail: [email protected]
Date: 2010/4/6
实验目的:练习vi,使用UNIX的系统调用和库函数,体会UNIX文件通配符的处理方式以及命令对选项的处理方式。
编程实现程序list.c,列表普通磁盘文件(不考虑目录和设备文件等),列出文件名和文件大小。
与ls命令类似,命令行参数可以有0到多个
0个参数:列出当前目录下所有文件
参数为普通文件:列出文件
参数为目录:列出目录下所有文件
实现自定义选项r,a,l,h,m以及--
r 递归方式列出子目录
a 列出文件名第一个字符为圆点的普通文件(默认情况下不列出文件名首字符为圆点的文件)
l 后跟一整数,限定文件大小的最小值(字节)
h 后跟一整数,限定文件大小的最大值(字节)
m 后跟一整数n,限定文件的最近修改时间必须在n天内
-- 显式地终止命令选项分析
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
slective options about ls
rflag is about recursive
aflag is about ones with . infront
lflag is about the minimum size
hflag is about the maximum size
mflag is about the modified time
*/
int rflag, aflag, lflag, hflag, mflag;
long modified_time; //the last time file be modified, days ago
off_t lower_size; //file's minimum size
off_t upper_size; //file's maximum size
/*
set the flags, thus the ls option
*/
void getoptions(int argc, char *argv[])
{
char ch;
//clear, all unseted
rflag = 0; aflag = 0; lflag = 0; hflag = 0; mflag = 0;
//use getopt to get the options, want to know more, call man
//the last one or after -- was set in argv[optind]
while ((ch = getopt(argc, argv, "ral:h:m:")) != -1) {
switch (ch) {
case 'r': rflag = 1; break;
case 'a': aflag = 1; break;
case 'l': lflag = 1; lower_size = atol(optarg); break;
case 'h': hflag = 1; upper_size = atol(optarg); break;
case 'm': mflag = 1; modified_time = atol(optarg); break; //get days
case '?': printf("Unknown option: %c\n", (char)optopt); break;
default : printf("Step into default\n"); break;
}
}
}
/*
the function to list things in path
*/
int ls(char *path)
{
struct stat st; //for check this is a directory or file
char temp[100]; //if path is null, it is used to get current directory
// get the path
if (path == NULL || path[0] == '-') {
path = temp;
getcwd(path, 100);
}
/* open the inode of file */
if (lstat(path, &st)) {
fprintf(stderr, "Error: %s not exist.\n", path);
return (-1);
}
/* judge whether the file is a file or a directory */
if (S_ISDIR(st.st_mode)) {
ls_dir(path);
}
else if (S_ISREG(st.st_mode)) {
print(path);
}
else {
printf("Not ordinary file, wouldn't be listed.\n");
}
return 0;
}
/*
list dirs, may recursively or not, depending on rflag
one thing is sure that it will list directories and files first,
then consider the things in the directories
*/
int ls_dir(char *path)
{
DIR *dp = NULL;
struct dirent *dirp = NULL;
if (path[0] != '.' || (path[0] == '.' && aflag == 1)) {
printf("\n%s:\n****************************************\n", path);
/* open the directory */
if ((dp = opendir(path)) == NULL) {
fprintf(stderr, "Error: can't open directory %s!\n", path);
return (-1);
}
chdir(path);
/* list all the things in directory */
while ((dirp = readdir(dp)) != NULL) {
print(dirp->d_name);
}
/* recursively ls dirs, after ls things together,
it's time to list things in children directory */
if (rflag == 1) {
rewinddir(dp); //reset dp
while ((dirp = readdir(dp)) != NULL) {
if (strcmp(dirp->d_name, ".") == 0
|| strcmp(dirp->d_name, "..") == 0) { //no current and parent directory
continue;
}
ls_dir_r(dirp->d_name); //only list directories, judged inside the function
}
}
/* close the directory */
if (closedir(dp)) {
fprintf(stderr, "Error: can't close the directory %s!\n", path);
return -1;
}
chdir("..");
}
return 0;
}
/*
list directories recursively,
only directories, nomatter what path you put in
*/
int ls_dir_r(char *path)
{
struct stat st;
/* open the inode of file */
if (lstat(path, &st)) {
fprintf(stderr, "Error: %s not exist.\n", path);
return (-1);
}
/* only ls directories */
if (S_ISDIR(st.st_mode)) {
ls_dir(path);
}
}
/*
print the filetype/size/name on the screen
*/
int print(char *path)
{
struct stat st;
time_t tp;
char *filename = NULL;
//get current time
time(&tp);
if (lstat(path, &st)) {
fprintf(stderr, "Error: %s can't be opened.\n", path);
return (-1);
}
/* get file name */
if ((filename = strrchr(path, '/')) != NULL) {
filename++;
}
else {
filename = path;
}
/* judge whether to list the file */
if ((S_ISDIR(st.st_mode)|| S_ISREG(st.st_mode)) //only directories and normal files
&& (lflag == 0 || (lflag == 1 && (st.st_size >= lower_size))) //the min size
&& (hflag == 0 || (hflag == 1 && (st.st_size <= upper_size))) //the max size
&& (mflag == 0 || (mflag == 1 && ((tp - st.st_mtime) <= modified_time * 24 * 60 * 60))) //modified time
&& (aflag == 1 || (aflag == 0 && filename[0] != '.')) //file with a '.' infront
) {
printf("%s\t%10ld\t%s\n", (S_ISDIR(st.st_mode) ? "DIR": "FILE"), st.st_size, filename);
}
return 0;
}
/*
The main function
*/
int main(int argc, char *argv[])
{
getoptions(argc, argv);
ls(argv[optind]);
return 0;
}
6. Linux 下C语言编程题!
1.#include<stdio.h>
#include<string.h>
#include<malloc.h>
main()
{ char *s,*h,*t;int l;
s=(char*)malloc(20*sizeof(char));
printf("input a string:");
scanf("%s",s);
l=strlen(s);/*求字符串长度赋给l*/
h=s;t=s+l-1; /*h指针指向第一个字符,t指向最后一个*/
for(;h<t;h++,t--) /*从头尾向中比较*/
{if((*h)!=(*t)){printf("not symmetric");break;} /*发现不同的字符,显示不对称,并结束比较*/
}if(h>=t)printf("symmetric"); /*如果比较完了,则显示对称*/
getch();
}
2.#include<stdio.h>
#include<string.h>
#include<malloc.h>
main()
{ char *s,*p,*q;
s=(char*)malloc(20*sizeof(char));
printf("input string:");
scanf("%s",s);
p=s;
while(*p)
{if(*p=='a'||*p=='e'||*p=='i'||*p=='o'
||*p=='u')
{q=p;/*让q指针和q指针指向同一个字符*/
while(*q)
{*q=*(q+1);q++;} /*将当前字符后面的字符前移,相当于把p指着的当前字符删除*/
p--;}
p++;}
printf("%s",s);
getch();
}
3.#include<stdio.h>
#include<string.h>
main()
{ int a,i=0,s=0;char b[52],c[100],t;
for(t='A';t<='Z';t++)
b[i++]=t;
for(t='a';t<='z';t++)
b[i++]=t;
for(i=0;i<52;i++)
printf("%c",b[i]);/*将52个大小写字母存入数组b中*/
srand(time(NULL)); /*使每次随机产生的数不同*/
for(i=0;i<100;i++) /*循环100次,产生100个随机字母*/
{ a=rand()%51; /*每次从0到51中产生一个随机数,从而从b〔0〕到b〔51〕中选出一个字母*/
c[i]=b[a]; /*每次产生的随机字母存入数组c中*/
if(b[a]=='a'||b[a]=='e'||b[a]=='i'||
b[a]=='o'||b[a]=='u'||b[a]=='A'||
b[a]=='E'||b[a]=='I'||b[a]=='O'||b[a]
=='U')s++; /*当是元音字母时,用s来统计个数*/
}
printf("\n");
for(i=0;i<100;i++)printf("%c ",c[i]);
printf("\ns:%d",s);
getch();
}
7. 想从事Linux下C编程,我应该都学些什么
C语言程序设计
LINUX操作系统
LINUX程序设计
SHELL程序设计
8. LinuxC编程一站式学习的目 录
上篇 C语言入门
第1章 程序的基本概念 2
1.1 程序和编程语言 2
1.2 自然语言和形式语言 6
1.3 程序的调试 7
1.4 第一个程序 9
第2章 常量、变量和表达式 12
2.1 继续Hello World 12
2.2 常量 15
2.3 变量 16
2.4 赋值 18
2.5 表达式 19
2.6 字符类型与字符编码 23
第3章 简单函数 24
3.1 数学函数 24
3.2 自定义函数 26
3.3 形参和实参 31
3.4 全局变量、局部变量和作用域 35
第4章 分支语句 41
4.1 if语句 41
4.2 if/else语句 43
4.3 布尔代数 45
4.4 switch语句 49
第5章 深入理解函数 51
5.1 return语句 51
5.2 增量式开发 54
5.3 递归 58
第6章 循环语句 64
6.1 while语句 64
6.2 do/while语句 66
6.3 for语句 67
6.4 break和continue语句 69
6.5 嵌套循环 70
6.6 goto语句和标号 71
第7章 结构体 74
7.1 复合类型与结构体 74
7.2 数据抽象 78
7.3 数据类型标志 82
7.4 嵌套结构体 84
第8章 数组 85
8.1 数组的基本概念 85
8.2 数组应用实例:统计随机数 88
8.3 数组应用实例:直方图 91
8.4 字符串 94
8.5 多维数组 95
第9章 编码风格 100
9.1 缩进和空白 100
9.2 注释 104
9.3 标识符命名 107
9.4 函数 108
9.5 indent工具 108
第10章 gdb 110
10.1 单步执行和跟踪函数调用 110
10.2 断点 117
10.3 观察点 121
10.4 段错误 125
第11章 排序与查找 128
11.1 算法的概念 128
11.2 插入排序 129
11.3 算法的时间复杂度分析 131
11.4 归并排序 133
11.5 线性查找 138
11.6 折半查找 139
第12章 栈与队列 144
12.1 数据结构的概念 144
12.2 堆栈 144
12.3 深度优先搜索 146
12.4 队列与广度优先搜索 152
12.5 环形队列 156
本阶段总结 159
下篇 C语言本质
第13章 计算机中数的表示 162
13.1 为什么计算机用二进制计数 162
13.2 不同进制之间的换算 164
13.3 整数的加减运算 165
13.3.1 Sign and Magnitude表示法 165
13.3.2 1's Complement表示法 166
13.3.3 2's Complement表示法 167
13.3.4 有符号数和无符号数 168
13.4 浮点数 169
第14章 数据类型详解 172
14.1 整型 172
14.2 浮点型 176
14.3 类型转换 177
14.3.1 Integer Promotion 177
14.3.2 Usual Arithmetic Conversion 178
14.3.3 由赋值产生的类型转换 179
14.3.4 强制类型转换 179
14.3.5 编译器如何处理类型转换 179
第15章 运算符详解 182
15.1 位运算 182
15.1.1 按位与、或、异或、取反运算 182
15.1.2 移位运算 183
15.1.3 掩码 184
15.1.4 异或运算的一些特性 185
15.2 其他运算符 186
15.2.1 复合赋值运算符 186
15.2.2 条件运算符 186
15.2.3 逗号运算符 187
15.2.4 sizeof运算符与typedef类型声明 187
15.3 Side Effect与Sequence Point 189
15.4 运算符总结 191
第16章 计算机体系结构基础 193
16.1 内存与地址 193
16.2 CPU 193
16.3 设备 196
16.4 MMU 198
16.5 Memory Hierarchy 201
第17章 x86汇编程序基础 205
17.1 最简单的汇编程序 205
17.2 x86的寄存器 208
17.3 第二个汇编程序 209
17.4 寻址方式 211
17.5 ELF文件 212
17.5.1 目标文件 213
17.5.2 可执行文件 218
第18章 汇编与C之间的关系 224
18.1 函数调用 224
18.2 main函数、启动例程和退出状态 230
18.3 变量的存储布局 237
18.4 结构体和联合体 244
18.5 C内联汇编 248
18.6 volatile限定符 250
第19章 链接详解 255
19.1 多目标文件的链接 255
19.2 定义和声明 260
19.2.1 extern和static关键字 260
19.2.2 头文件 264
19.2.3 定义和声明的详细规则 268
19.3 静态库 271
19.4 共享库 274
19.4.1 编译、链接、运行 274
19.4.2 函数的动态链接过程 281
19.4.3 共享库的命名惯例 282
19.5 虚拟内存管理 284
第20章 预处理 290
20.1 预处理的步骤 290
20.2 宏定义 291
20.2.1 函数式宏定义 291
20.2.2 内联函数 294
20.2.3 #、##运算符和可变参数 296
20.2.4 #undef预处理指示 298
20.2.5 宏展开的步骤 299
20.3 条件预处理指示 300
20.4 其他预处理特性 303
第21章 Makefile基础 306
21.1 基本规则 306
21.2 隐含规则和模式规则 313
21.3 变量 317
21.4 自动处理头文件的依赖关系 321
21.5 常用的make命令行选项 324
第22章 指针 327
22.1 指针的基本概念 327
22.2 指针类型的参数和返回值 331
22.3 指针与数组 332
22.4 指针与const限定符 335
22.5 指针与结构体 337
22.6 指向指针的指针与指针数组 337
22.7 指向数组的指针与多维数组 340
22.8 函数类型和函数指针类型 341
22.9 不完全类型和复杂声明 344
第23章 函数接口 349
23.1 本章的预备知识 349
23.1.1 strcpy与strncpy 349
23.1.2 malloc与free 354
23.2 传入参数与传出参数 358
23.3 两层指针的参数 360
23.4 返回值是指针的情况 362
23.5 回调函数 365
23.6 可变参数 368
第24章 C标准库 372
24.1 字符串操作函数 373
24.1.1 给字符串赋初值 373
24.1.2 取字符串的长度 374
24.1.3 拷贝字符串 375
24.1.4 连接字符串 377
24.1.5 比较字符串 378
24.1.6 搜索字符串 379
24.1.7 分割字符串 380
24.2 标准I/O库函数 383
24.2.1 文件的基本概念 383
24.2.2 fopen/fclose 384
24.2.3 stdin/stdout/stderr 387
24.2.4 errno与perror/strerror函数 388
24.2.5 以字节为单位的I/O函数 391
24.2.6 操作读写位置的函数 393
24.2.7 以字符串为单位的I/O函数 395
24.2.8 以记录为单位的I/O函数 397
24.2.9 格式化I/O函数 399
24.2.10 C标准库的I/O缓冲区 406
24.2.11 本节综合练习 410
24.3 数值字符串转换函数 412
24.4 分配内存的函数 414
第25章 链表、二叉树和哈希表 415
25.1 链表 415
25.1.1 单链表 415
25.1.2 双向链表 421
25.1.3 静态链表 425
25.1.4 本节综合练习 426
25.2 二叉树 426
25.2.1 二叉树的基本概念 426
25.2.2 排序二叉树 432
25.3 哈希表 437
本阶段总结 439
附录A 字符编码 442
索引 449
参考书目 474
9. linux操作系统上c语言编程入门怎么解决
Linux程序设计入门--进程介绍
Linux下进程的创建
前言:
这篇文章是用来介绍在Linux下和进程相关的各个概念.我们将会学到:
进程的概念
进程的身份
进程的创建
守护进程的创建
----------------------------------------
----
1。进程的概念
Linux操作系统是面向多用户的.在同一时间可以有许多用户向操作系统发出各种命
令.那么操作系统是怎么实现多用户的环境呢? 在现代的操作系统里面,都有程序和进程
的概念.那么什么是程序,什么是进程呢? 通俗的讲程序是一个包含可以执行代码的文件
,是一个静态的文件.而进程是一个开始执行但是还没有结束的程序的实例.就是可执行文
件的具体实现. 一个程序可能有许多进程,而每一个进程又可以有许多子进程.依次循环
下去,而产生子孙进程. 当程序被系统调用到内存以后,系统会给程序分配一定的资源(内
存,设备等等)然后进行一系列的复杂操作,使程序变成进程以供系统调用.在系统里面只
有进程没有程序,为了区分各个不同的进程,系统给每一个进程分配了一个ID(就象我们的
身份证)以便识别. 为了充分的利用资源,系统还对进程区分了不同的状态.将进程分为新
建,运行,阻塞,就绪和完成五个状态. 新建表示进程正在被创建,运行是进程正在运行,阻
塞是进程正在等待某一个事件发生,就绪是表示系统正在等待CPU来执行命令,而完成表示
进程已经结束了系统正在回收资源. 关于进程五个状态的详细解说我们可以看《操作系
统》上面有详细的解说。
2。进程的标志
上面我们知道了进程都有一个ID,那么我们怎么得到进程的ID呢?系统调用getpid可
以得到进程的ID,而getppid可以得到父进程(创建调用该函数进程的进程)的ID.
#include <unistd>
pid_t getpid(void);
pid_t getppid(void);
进程是为程序服务的,而程序是为了用户服务的.系统为了找到进程的用户名,还为进程和
用户建立联系.这个用户称为进程的所有者.相应的每一个用户也有一个用户ID.通过系统
调用getuid可以得到进程的所有者的ID.由于进程要用到一些资源,而Linux对系统资源是
进行保护的,为了获取一定资源进程还有一个有效用户ID.这个ID和系统的资源使用有关
,涉及到进程的权限. 通过系统调用geteuid我们可以得到进程的有效用户ID. 和用户ID
相对应进程还有一个组ID和有效组ID系统调用getgid和getegid可以分别得到组ID和有效
组ID
#include <unistd>
#include <sys/types.h>
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
git_t getegid(void);
有时候我们还会对用户的其他信息感兴趣(登录名等等),这个时候我们可以调用getpwui
d来得到.
struct passwd {
char *pw_name; /* 登录名称 */
char *pw_passwd; /* 登录口令 */
uid_t pw_uid; /* 用户ID */
gid_t pw_gid; /* 用户组ID */
char *pw_gecos; /* 用户的真名 */
char *pw_dir; /* 用户的目录 */
char *pw_shell; /* 用户的SHELL */
};
#include <pwd.h>
#include <sys/types.h>
struct passwd *getpwuid(uid_t uid);
下面我们学习一个实例来实践一下上面我们所学习的几个函数:
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc,char **argv)
{
pid_t my_pid,parent_pid;
uid_t my_uid,my_euid;
gid_t my_gid,my_egid;
struct passwd *my_info;
my_pid=getpid();
parent_pid=getppid();
my_uid=getuid();
my_euid=geteuid();
my_gid=getgid();
my_egid=getegid();
my_info=getpwuid(my_uid);
printf("Process ID:%ld/n",my_pid);
printf("Parent ID:%ld/n",parent_pid);
printf("User ID:%ld/n",my_uid);
printf("Effective User ID:%ld/n",my_euid);
printf("Group ID:%ld/n",my_gid);
printf("Effective Group ID:%ld/n",my_egid):
if(my_info)
{
printf("My Login Name:%s/n" ,my_info->pw_name);
printf("My Password :%s/n" ,my_info->pw_passwd);
printf("My User ID :%ld/n",my_info->pw_uid);
printf("My Group ID :%ld/n",my_info->pw_gid);
printf("My Real Name:%s/n" ,my_info->pw_gecos);
printf("My Home Dir :%s/n", my_info->pw_dir);
printf("My Work Shell:%s/n", my_info->pw_shell);
}
}
3。进程的创建
创建一个进程的系统调用很简单.我们只要调用fork函数就可以了.
#include <unistd.h>
pid_t fork();
当一个进程调用了fork以后,系统会创建一个子进程.这个子进程和父进程不同的地方只
有他的进程ID和父进程ID,其他的都是一样.就象符进程克隆(clone)自己一样.当然创建
两个一模一样的进程是没有意义的.为了区分父进程和子进程,我们必须跟踪fork的返回
值. 当fork掉用失败的时候(内存不足或者是用户的最大进程数已到)fork返回-1,否则f
ork的返回值有重要的作用.对于父进程fork返回子进程的ID,而对于fork子进程返回0.我
们就是根据这个返回值来区分父子进程的. 父进程为什么要创建子进程呢?前面我们已经
说过了Linux是一个多用户操作系统,在同一时间会有许多的用户在争夺系统的资源.有时
进程为了早一点完成任务就创建子进程来争夺资源. 一旦子进程被创建,父子进程一起从
fork处继续执行,相互竞争系统的资源.有时候我们希望子进程继续执行,而父进程阻塞直
到子进程完成任务.这个时候我们可以调用wait或者waitpid系统调用.
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid,int *stat_loc,int options);
wait系统调用会使父进程阻塞直到一个子进程结束或者是父进程接受到了一个信号.如果
没有父进程没有子进程或者他的子进程已经结束了wait回立即返回.成功时(因一个子进
程结束)wait将返回子进程的ID,否则返回-1,并设置全局变量errno.stat_loc是子进程的
退出状态.子进程调用exit,_exit 或者是return来设置这个值. 为了得到这个值Linux定
义了几个宏来测试这个返回值.
WIFEXITED:判断子进程退出值是非0
WEXITSTATUS:判断子进程的退出值(当子进程退出时非0).
WIFSIGNALED:子进程由于有没有获得的信号而退出.
WTERMSIG:子进程没有获得的信号号(在WIFSIGNALED为真时才有意义).
waitpid等待指定的子进程直到子进程返回.如果pid为正值则等待指定的进程(pid).如果
为0则等待任何一个组ID和调用者的组ID相同的进程.为-1时等同于wait调用.小于-1时等
待任何一个组ID等于pid绝对值的进程. stat_loc和wait的意义一样. options可以决定
父进程的状态.可以取两个值 WNOHANG:父进程立即返回当没有子进程存在时. WUNTACHE
D:当子进程结束时waitpid返回,但是子进程的退出状态不可得到.
父进程创建子进程后,子进程一般要执行不同的程序.为了调用系统程序,我们可以使用系
统调用exec族调用.exec族调用有着5个函数.
#include <unistd.h>
int execl(const char *path,const char *arg,...);
int execlp(const char *file,const char *arg,...);
int execle(const char *path,const char *arg,...);
int execv(const char *path,char *const argv[]);
int execvp(const char *file,char *const argv[]):
exec族调用可以执行给定程序.关于exec族调用的详细解说可以参考系统手册(man exec
l). 下面我们来学习一个实例.注意编译的时候要加 -lm以便连接数学函数库.
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <math.h>
void main(void)
{
pid_t child;
int status;
printf("This will demostrate how to get child status/n");
if((child=fork())==-1)
{
printf("Fork Error :%s/n",strerror(errno));
exit(1);
}
else if(child==0)
{
int i;
printf("I am the child:%ld/n",getpid());
for(i=0;i<1000000;i++) sin(i);
i=5;
printf("I exit with %d/n",i);
exit(i);
}
while(((child=wait(&status))==-1)&(errno==EINTR));
if(child==-1)
printf("Wait Error:%s/n",strerror(errno));
else if(!status)
printf("Child %ld terminated normally return status is zero/n",
child);
else if(WIFEXITED(status))
printf("Child %ld terminated normally return status is %d/n",
child,WEXITSTATUS(status));
else if(WIFSIGNALED(status))
printf("Child %ld terminated e to signal %d znot caught/n",
child,WTERMSIG(status));
}
strerror函数会返回一个指定的错误号的错误信息的字符串.
4。守护进程的创建
如果你在DOS时代编写过程序,那么你也许知道在DOS下为了编写一个常驻内存的程序
我们要编写多少代码了.相反如果在Linux下编写一个"常驻内存"的程序却是很容易的.我
们只要几行代码就可以做到. 实际上由于Linux是多任务操作系统,我们就是不编写代码
也可以把一个程序放到后台去执行的.我们只要在命令后面加上&符号SHELL就会把我们的
程序放到后台去运行的. 这里我们"开发"一个后台检查邮件的程序.这个程序每个一个指
定的时间回去检查我们的邮箱,如果发现我们有邮件了,会不断的报警(通过机箱上的小喇
叭来发出声音). 后面有这个函数的加强版本加强版本
后台进程的创建思想: 首先父进程创建一个子进程.然后子进程杀死父进程(是不是很无
情?). 信号处理所有的工作由子进程来处理.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
/* Linux 的默任个人的邮箱地址是 /var/spool/mail/用户的登录名 */
#define MAIL "/var/spool/mail/hoyt"
/* 睡眠10秒钟 */
#define SLEEP_TIME 10
main(void)
{
pid_t child;
if((child=fork())==-1)
{
printf("Fork Error:%s/n",strerror(errno));
exit(1);
}
else if(child>0)
while(1);
if(kill(getppid(),SIGTERM)==-1)
{
printf("Kill Parent Error:%s/n",strerror(errno));
exit(1);
}
{
int mailfd;
while(1)
{
if((mailfd=open(MAIL,O_RDONLY))!=-1)
{
fprintf(stderr,"%s","7");
close(mailfd);
}
sleep(SLEEP_TIME);
}
}
}
你可以在默认的路径下创建你的邮箱文件,然后测试一下这个程序.当然这个程序还有很
多地方要改善的.我们后面会对这个小程序改善的,再看我的改善之前你可以尝试自己改
善一下.比如让用户指定邮相的路径和睡眠时间等等.相信自己可以做到的.动手吧,勇敢
的探险者.
好了进程一节的内容我们就先学到这里了.进程是一个非常重要的概念,许多的程序都会
用子进程.创建一个子进程是每一个程序员的基本要求!
10. linux下c应该怎么学,新手
这个问题应该分成2问,也就是说学习过程应该分成相应的两步:
1、C言语如何学习;2、如何在linux下编译C程序。
第一个问题简单说来就是好的入门教程+高级教程+经典实例练习,入门教程是前提,如果什么都不知道的话无论是在linux下还是其他系统下都是一片茫然;
第二个问题简单说来就是学会gcc,gdb,make,makefile的用法,这个比较容易,在C言语入门教程学完后花很少时间熟悉一下就会用了。