一、dup、dup2
int dup(int oldfd);
int dup2(int oldfd,int newfd);
dup函数创建一个新的文件描述符,该新文件描述符和原文件描述符指向相同的文件、管道或者网络连接,并且dup返回的新文件描述符是取系统当前可用的最小整数值,dup2和dup类似,不过它返回的是第一个不小于新文件描述符的整数值,dup和dup2调用失败时都返回-1并设置errno
二、stdin、stdout、stderr和STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO的区别和联系
stdin类型为 FILE*
 STDIN_FILENO类型为 int三、浅谈printf、fprintf、sprintf的使用和区别


fprintf可以把数据写入文件中,借助的是第一个参数(FILE*的指针)
fprintf比printf也只多了一个FILE*指针,后面两个参数和printf一样写就行
sprintf的作用:
 官方点: sprintf的作用是将一个格式化的字符串输出到一个目的字符串中
参数里的buffer指针就是指向目的字符串的
 简单点:把数据输出到一个字符串四、Linux access函数讲解
#include<unistd.h>
int access(const char* pathname, int mode);
参数介绍:
    pathname 是文件的路径名+文件名
    mode:指定access的作用,取值如下
F_OK 值为0,判断文件是否存在
  
 X_OK 值为1,判断对文件是可执行权限
  
 W_OK 值为2,判断对文件是否有写权限
  
 R_OK 值为4,判断对文件是否有读权限
  
 注:后三种可以使用或“|”的方式,一起使用,如W_OK|R_OK
五、C语言strlen与sizeof的区别详解
strlen 是一个函数,它用来计算指定字符串 str 的长度,但不包括结束字符(即 null 字符)。
六、进程
1、fork()创建进程、复制地址空间
子进程返回0,父进程返回子进程pid
2、sleep()进程挂起
3、wait()、waitpid()进程收尸、等待进程
4、exit()、_exit()进程结束
5、exit库函数、_exit函数系统调用
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[]);
                 解析:
                     1>exec函数族一共有6个成员 
                     2>exec函数族都是exec开头
                     
                     不带p :根据路径来加载程序
                     带p   :根据(执行目录)文件名来加载程序 默认路径:/usr/bin     和 /bin 用来保存命令            
                     带l      :根据列举来加载程序    --->直接提供参数 
                     带v   :根据数组来加载程序     --->将参数塞入到数组中,并以数组作为参数给函数
                     带e   :根据环境变量加载程序后传递某些数据
                     
                 exec失败返回-1,并设置错误码七、进程通信
1、有名管道
mkfifo("./fifo",0777)创建有名管道
2、无名管道
只适用于父子进程
char pp[1];
pipe(pp)创建无名管道
3、信号
唯一异步通信,类似中断。
raise()发信号给自身进程
alarm()闹钟
kill()发信号
pause()等待信号
signal()注册信号
4、消息队列
ipcs  -q
ipcrm -q  <id>
 int msgget(key_t key, int msgflg);   //创建或获取消息队列
     //参数1 ---- 消息队列的key:
                 方法一:IPC_PRIVATE  ---- 系统自动分配key
                 方法二:调用函数ftok ---返回key值
                 key_t ftok(const char *pathname, int proj_id);
                 //参数1 ---- 字符串,表示工程路径
                 //参数2 ---- 工程编号
                 //返回值----成功:key,失败:-1
     //参数2 ----- 消息队列的权限,一般为: IPC_CREAT | 0666
    IPC_CREAT    如果key不存在,则创建(类似open函数的O_CREAT)
    IPC_EXCL       如果key存在,则返回失败(类似open函数的O_EXCL)
    IPC_NOWAIT  如果需要等待,则直接返回错误
     //返回值 ---- 成功:消息队列的ID,失败:-1 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
     //参数1 ----- 消息队列ID
     //参数2 ----- 结构体struct msgbuf 类型的指针 ,,该结构体需要自定义
                   struct msgbuf {
                        long mtype;       /* message type, must be > 0 */  消息类型
                        char mtext[1];    /* message data */   消息正文
                    };
     //参数3 ----- 消息正文的实际字符长度
     //参数4 ----- 发送方式:
                     IPC_NOWAIT  消息没有发送完成函数也会立即返回。
                     0:直到发送完成函数才返回
       //返回值 ------ 成功:0,失败:-1    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
     //参数1 ----- 消息队列ID
     //参数2 ----- 结构体struct msgbuf 类型的指针 ,,该结构体需要自定义
                   struct msgbuf {
                        long mtype;       /* message type, must be > 0 */  消息类型
                        char mtext[1];    /* message data */   消息正文
                    };
     //参数3 ----- 消息正文的长度
     //参数4 ----- 要接收的消息的类型msgtyp
                      msgtyp = 0,表示接收消息队列中第一个消息(按顺序接收所有类型消息)
                      msgtyp > 0,表示接收指定类型的消息
                      msgtyp < 0,表示接收消息类型不大于msgtyp的绝对值的最小消息
     //参数5 ----- 发送方式:
                     IPC_NOWAIT  消息没有发送完成函数也会立即返回。
                     0:直到发送完成函数才返回
       //返回值 ------ 成功:接收的消息的字节数,失败:-1    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
     //参数1 ---- 消息队列ID
     //参数2 ---- 命令:cmd
                     IPC_STAT ---- 获取消息队列属性
                     IPC_SET  ---- 设置消息队列属性
                     IPC_RMID ---- 删除消息队列
     //参数2 ---- 如果mcd不是IPC_RMID,则需要该参数,struct msqid_ds结构体指针
                 struct msqid_ds {
                    struct ipc_perm msg_perm;     /* Ownership and permissions */
                    time_t          msg_stime;    /* Time of last msgsnd(2) */
                    time_t          msg_rtime;    /* Time of last msgrcv(2) */
                    time_t          msg_ctime;    /* Time of last change */
                    unsigned long   __msg_cbytes; /* Current number of bytes in
                                                     queue (nonstandard) */
                    msgqnum_t       msg_qnum;     /* Current number of messages
                                                     in queue */
                    msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                     allowed in queue */
                    pid_t           msg_lspid;    /* PID of last msgsnd(2) */
                    pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
                };
     //返回值 ---成功:0,失败:-15、共享内存
ipcs -m
  int shmget(key_t key, size_t size, int shmflg);
    //参数1 ---- 共享内存的key:
                 方法一:IPC_PRIVATE  ---- 系统自动分配key
                 方法二:调用函数ftok ---返回key值
                 key_t ftok(const char *pathname, int proj_id);
                 //参数1 ---- 字符串,表示工程路径
                 //参数2 ---- 工程编号
                 //返回值----成功:key,失败:-1
     //参数2 ----- 共享内存的大小
     //参数3 ----- 共享内存的权限,一般为: IPC_CREAT | 0666
     //返回值 ---- 成功:共享内存的ID,失败:-1    void *shmat(int shmid, const void *shmaddr, int shmflg);
    //参数1 ---- 共享内存id
     //参数2 ---- 指定映射虚拟空间地址,但是,一般为NULL,由系统自动映射
     //参数3 ---- 共享内存使用权限
                     SHM_RDONLY:共享内存只读
                     默认0:共享内存可读写
     //返回值 -----成功:映射的虚拟空间地址,失败:-1   int shmdt(const void *shmaddr);
     //参数 ------映射的进程的虚拟地址,也就是shmat()返回的地址
     //返回值 ----- 成功:0,失败:-1   int shmctl(int shmid, int cmd, struct shmid_ds *buf);
     //参数1 ---- 共享内存ID
     //参数2 ---- 命令:cmd
                     IPC_STAT ---- 获取共享内存属性
                     IPC_SET  ---- 设置共享内存属性
                     IPC_RMID ---- 删除共享内存
     //参数2 ---- 如果mcd不是IPC_RMID,则需要该参数,struct msqid_ds结构体指针
                 struct shmid_ds {
                    struct ipc_perm shm_perm;    /* Ownership and permissions */
                    size_t          shm_segsz;   /* Size of segment (bytes) */
                    time_t          shm_atime;   /* Last attach time */
                    time_t          shm_dtime;   /* Last detach time */
                    time_t          shm_ctime;   /* Last change time */
                    pid_t           shm_cpid;    /* PID of creator */
                    pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
                    shmatt_t        shm_nattch;  /* No. of current attaches */
                    ...
                };    //返回值 ---成功:0,失败:-1
6、信号量
信号灯(semaphore),也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制
信号灯种类:
     posix有名信号灯
     posix基于内存的信号灯(无名信号灯)
     System V信号灯(IPC对象)
从使用上分为二值信号灯和计数信号灯两种:1》 二值信号灯 -----表示资源是否可用
     值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。
 2》计数信号灯 -----表示资源数量
     值在0到n之间。用来统计资源,其值代表可用资源数用信号灯实现进程的同步,需要实现两个操作
 3》等待操作
     等待操作也叫P操作,等待信号灯的值变为大于0,然后将其减1;
 4》释放操作
     释放操作也叫V操作,用来唤醒等待资源的进程或者线程
 5》System V的信号灯
     是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。int semget(key_t key, int nsems, int semflg);
     //参数1 ---- 信号灯的key:
                 方法一:IPC_PRIVATE  ---- 系统自动分配key
                 方法二:调用函数ftok ---返回key值
                 key_t ftok(const char *pathname, int proj_id);
                 //参数1 ---- 字符串,表示工程路径
                 //参数2 ---- 工程编号
                 //返回值----成功:key,失败:-1
     //参数2 ----- 信号灯对象(集合)中的信号灯的个数
     //参数3 ----- 信号灯的权限,一般为: IPC_CREAT | 0666
     //返回值 ---- 成功:信号灯的ID,失败:-1    int semop(int semid, struct sembuf *sops, size_t nsops);
     //参数1 ----- 信号灯对象的ID
     //参数2 ----- 结构体struct sembuf的指针
                 struct sembuf {
                         unsigned short  sem_num;        /* semaphore index in array 操作的信号灯的下标 */
                         short           sem_op;         /* semaphore operation 
                                                         0 :  等待,直到信号灯的值变成0
                                                           1  :  释放资源,V操作
                                                         -1 :  分配资源,P操作*/
                         short           sem_flg;        /* operation flags:0,  IPC_NOWAIT,  SEM_UNDO */
                 };
     //参数3 ----要操作次数
     //返回值 -----成功:0,失败:-1  int semctl(int semid, int semnum, int cmd, ...);
     //参数1 ---- 信号灯对象ID
     //参数2 ---- 要操作的信号灯的编号
     //参数3 ---- 名称cmd:
                 GETVAL:获取一个信号灯的值
                 SETVAL:设置一个信号灯的值
                 IPC_RMID:从系统中删除信号灯集合
                 GETALL:获取所有信号灯的值
                 SETALL:设置所有信号灯的值
    //参数4 ----- 联合体,该联合体需要自定义,如下:
                    union semun {
                    int              val;    /* Value for SETVAL  设置一个信号灯的值时使用 */
                    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
                    unsigned short  *array;  /* Array for GETALL, SETALL 获取或设置所有信号灯的值时使用 */
                    struct seminfo  *__buf;  /* Buffer for IPC_INFO    (Linux-specific) */                  
                 };八、线程
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);   创建线程
    Compile and link with -pthread.    -------//如果程序中使用上面函数,编译时,需要链接库: -lpthread
     
     //参数1 ---- 保存线程ID的变量地址
     //参数2 ---- 线程属性,一般为NULL,默认属性
     //参数3 -----线程执行的函数(线程函数),格式必须为:
                     void* 线程函数名称(void * arg)    
                     {
                         //线程执行代码
                         ........
                     }
     //参数4 ---- 传给线程的参数
     //返回值 ----成功:0,失败:非0值  void pthread_exit(void *retval);   结束线程  //Compile and link with -pthread.
     //参数 -----线程返回的数据地址,该数据必须在线程返回后空间没有释放  #include <pthread.h>
    int pthread_join(pthread_t thread, void **retval);  线程收尸 // Compile and link with -pthread.
     //参数1 ----线程ID
     //参数2 ---- 保存线程返回值的指针的地址
     //返回值 --- 成功:0,失败:非0    int pthread_cancel(pthread_t thread);    //Compile and link with -pthread
     //参数 ---- 线程ID
     //返回值 ---- 成功:0,失败:非01》概念
     在创建线程时,默认为结合属性,当线程结束时,它不会自动释放资源,需要主线程调用pthread_join()来回收资源
     在创建线程时,也可以将线程的属性改为分离属性,此时,当线性结束时,会自动释放资源,此时不需要再调用pthread_join()
 设置线程的分离属性有两种方式:
 2》方式一:直接给pthread_create传递线程属性变量,设置分离属性
     int pthread_attr_init(pthread_attr_t *attr);  //初始化线程属性变量
     int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
     //参数1 ---- 属性变量地址
     //参数2 ---- 要设置的属性:
                     PTHREAD_CREATE_DETACHED   ---分离
                     PTHREAD_CREATE_JOINABLE   ---结合3》使用线程函数
     int pthread_detach(pthread_t thread);
     //参数 ---- 线程ID
     //返回值 ---- 成功:0,失败:非0
     pthread_t pthread_self(void);
 //返回调用该函数的线程的ID