📄 appendix_c.htm
字号:
<p>其保存在文档上。 </p>
<p>4.17 read改变了文件访问时间,为了消除这一影响,有些版本的file(1)调</p>
<p>用uti </p>
<p>me恢复文件的访问时间,但是这样做会修改文件的状态改变时间。 </p>
<p>4.18
内核对目录的深度没有内在的限制,但是如果路径名的长度超出了</p>
<p>PATH_MAX </p>
<p>有许多命令会失败。程序C.2创建了一个深度为100的目录树,每一级目录名</p>
<p>有45个 </p>
<p>字符。利用getcwd可以得到第100级目录的绝对路径名(需要多次调用</p>
<p>realloc申请 </p>
<p>一个足够大的缓存)。 </p>
<p>#include <sys/types.h> </p>
<p>#include <sys/stat.h> </p>
<p>#include <fcntl.h> </p>
<p>#include "ourhdr.h" </p>
<p>#define DEPTH 100 /* directory depth */ </p>
<p>#define MYHOME "/home/stevens" </p>
<p>#define NAME "alonglonglonglonglonglonglonglonglonglongname"</p>
<p>int </p>
<p>main(void) </p>
<p>{ </p>
<p>int i, size; </p>
<p>char *path; </p>
<p>if (chdir(MYHOME) < 0) </p>
<p>err_sys("chdir error"); </p>
<p>for (i = 0; i < DEPTH; i++) { </p>
<p>if (mkdir(NAME, DIR_MODE) < 0) </p>
<p>err_sys("mkdir failed, i = %d", i); </p>
<p>if (chdir(NAME) < 0) </p>
<p>err_sys("chdir failed, i = %d", i); </p>
<p>} </p>
<p>if (creat("afile", FILE_MODE) < 0) </p>
<p>err_sys("creat error"); </p>
<p>/* </p>
<p>* The deep directory is created, with a file at the leaf. </p>
<p>* Now let's try and obtain its pathname. </p>
<p>*/ </p>
<p>path = path_alloc(&size); </p>
<p>for ( ; ; ) { </p>
<p>if (getcwd(path, size) != NULL) </p>
<p>break; </p>
<p>else { </p>
<p>err_ret("getcwd failed, size = %d", size); </p>
<p>size += 100; </p>
<p>if ( (path = realloc(path, size)) == NULL) </p>
<p>err_sys("realloc error"); </p>
<p>} </p>
<p>} </p>
<p>printf("length = %d\n%s\n", strlen(path), path); </p>
<p>exit(0); </p>
<p>} </p>
<p>程序C.2 创建深度目录 </p>
<p>运行后得到: </p>
<p>$ a.out </p>
<p>getcwd failed, size = 1025: Result too large </p>
<p>getcwd failed, size = 1125: Result too large </p>
<p>… { 33行} </p>
<p>getcwd failed, size = 4525: Result too large </p>
<p>length = 4613 </p>
<p>{显示4613字节的路径名} </p>
<p>但是由于文件名太长了,不能用tar或cpio对该目录建立档案文件,而且也不</p>
<p>能用 </p>
<p>rm -r命令删除该目录。(我们怎样才能删除该目录树?) </p>
<p>4.19 /dev目录关闭了一般用户的写权限,所以用户不能删除目录中的文</p>
<p>件,即un </p>
<p>link失败。 </p>
<p> </p>
<p>第五章 </p>
<p>5.2 fgets函数读入数据,直到行结束或缓冲区满(当然会留出一个字节存放</p>
<p>'\0') </p>
<p>。同样,fputs只负责将缓冲区的内容输出,而并不考虑缓冲区中是否包含换</p>
<p>行符 </p>
<p>。所以,如果将MAXLINE设得很小,这两个函数仍然会正常工作,只不过被执</p>
<p>行的 </p>
<p>次数要比MAXLINE值较大的时候多。 </p>
<p>5.3 当printf没有输出任何字符时,如:printf("") ,返回0。 </p>
<p>5.4 这是一个比较常见的错误。getc以及getchar的返回值是整型,而不是</p>
<p>字符型 </p>
<p>。由于EOF经常定义为-1,那么如果系统使用的是有符号的字符类型,程序还</p>
<p>可以 </p>
<p>正常工作。但如果使用的是无符号字符类型,那么返回的EOF被保存到字符c</p>
<p>后将不 </p>
<p>再是-1,所以,程序会进入死循环。 </p>
<p>5.5 5个字符长的前缀、4个字符长的进程内唯一标识再加5个字符长的系统内</p>
<p>唯一 </p>
<p>标识(进程ID)刚好组成14位的UNIX传统文件长度限制。 </p>
<p>5.6 使用方法为:先调用fflush后调用fsync,fsync所使用的参数由</p>
<p>fileno函数获 </p>
<p>得。如果不调用fflush,所有的数据仍然在内存缓冲区中,此时调用fsync</p>
<p>将没有 </p>
<p>任何效果。 </p>
<p>5.7
当程序交互运行时,标准输入输出设备均为行缓冲方式。每次调用</p>
<p>fgets时标 </p>
<p>准输出设备将自动刷清。 </p>
<p> </p>
<p>第六章 </p>
<p>6.1 在SVR4系统中,用户手册中讲述了获取阴影密码文件的函数。我们不能</p>
<p>使用6 </p>
<p>..2节所述函数返回的pw_passwd变量来比较加密的口令。正确的方法是使用</p>
<p>阴影密 </p>
<p>码文件中对应用户的加密口令来进行比较。 </p>
<p>在4.3+ BSD系统中,密码文件的阴影是自动建立的。仅当调用者的用户ID为</p>
<p>0时, </p>
<p>getpwnam或getpwuid函数返回的passed结构中的pw_passwd字段才包含有</p>
<p>加密的口 </p>
<p>令。 </p>
<p>6.2 在SVR4系统中,程序C.3将输出加密的口令。当然,除非有超级用户权</p>
<p>限,否 </p>
<p>则调用getspnam将返回EACCESS错误。 </p>
<p>#include <sys/types.h> </p>
<p>#include <shadow.h> </p>
<p>#include "ourhdr.h" </p>
<p>int </p>
<p>main(void) /* SVR4 version */ </p>
<p>{ </p>
<p>struct spwd *ptr; </p>
<p>if ( (ptr = getspnam("stevens")) == NULL) </p>
<p>err_sys("getspnam error"); </p>
<p>printf("sp_pwdp = %s\n", </p>
<p>ptr->sp_pwdp == NULL || ptr->sp_pwdp[0] == 0 ? </p>
<p>"(null)" : ptr->sp_pwdp); </p>
<p>exit(0); </p>
<p>} </p>
<p>程序C.3 在SVR4系统中输出加密的口令 </p>
<p>在4.3+ BSD系统中,具有超级用户权限时,程序C.4将输出加密的口令。否</p>
<p>则pw_ </p>
<p>passed的返回值为星号(*)。 </p>
<p>#include <sys/types.h> </p>
<p>#include <pwd.h> </p>
<p>#include "ourhdr.h" </p>
<p>int </p>
<p>main(void) /* 44BSD version */ </p>
<p>{ </p>
<p>struct passwd *ptr; </p>
<p>if ( (ptr = getpwnam("stevens")) == NULL) </p>
<p>err_sys("getpwnam error"); </p>
<p>printf("pw_passwd = %s\n", </p>
<p>ptr->pw_passwd == NULL || ptr->pw_passwd[0] == 0 </p>
<p>? </p>
<p>"(null)" : ptr->pw_passwd); </p>
<p>exit(0); </p>
<p>} </p>
<p>程序C.4 在4.3+ BSD系统中输出加密的口令 </p>
<p>6.4 </p>
<p>#include <time.h> </p>
<p>#include "ourhdr.h" </p>
<p>int </p>
<p>main(void) </p>
<p>{ </p>
<p>time_t caltime; </p>
<p>struct tm *tm; </p>
<p>char line[MAXLINE]; </p>
<p>if ( (caltime = time(NULL)) == -1) </p>
<p>err_sys("time error"); </p>
<p>if ( (tm = localtime(&caltime)) == NULL) </p>
<p>err_sys("localtime error"); </p>
<p>if (strftime(line, MAXLINE, "%a %b %d %X %Z %Y\n", tm) == 0)</p>
<p>err_sys("strftime error"); </p>
<p>fputs(line, stdout); </p>
<p>exit(0); </p>
<p>} </p>
<p>程序C.5 以date(1)的格式输出日期和时间 </p>
<p>程序C.5的运行结果如下: </p>
<p>$ echo $TZ </p>
<p>MST7 </p>
<p>$ a.out </p>
<p>Wed Jan 15 06:48:57 MST 1992 </p>
<p>$ TZ=EST5EDT a.out U.S.East Coast </p>
<p>Wed Jan 15 08:49:06 EST 1992 </p>
<p>$ TZ=JST-9 a.out Japan </p>
<p>Wed Jan 15 22:49:12 JST 1992 </p>
<p> </p>
<p>第七章 </p>
<p>7.1 原因在于printf的返回值(输出的字符数)变成了main函数的返回码。当</p>
<p>然,并 </p>
<p>不是所有的系统都会出现该情况。 </p>
<p>7.2
当程序处于交互运行方式时,标准输出设备通常处于行缓冲方式,所以</p>
<p>当键入 </p>
<p>新行符时,上次的结果才被真正输出。如果标准输出设备被定向到一个文件而</p>
<p>处于 </p>
<p>完全缓冲方式,则当标准I/O清理操作执行时,结果才真正被输出。
</p>
<p>7.3 由于agrc和argv不象environ一样保存在全局变量中,所以在大多数</p>
<p>Unix系统 </p>
<p>中没有其它办法。 </p>
<p>7.4 当C程序复引用一个空指针出错时,执行该程序的进程将终止,于是可以</p>
<p>利用 </p>
<p>这种方法终止进程。 </p>
<p>7.5 定义如下: </p>
<p>typedef void Exitfunc ( void ) ; </p>
<p>int atexit ( Exitfunc *func ) ; </p>
<p>7.6 calloc将分配的内存空间初始化为0。但是ANSI C并不保证0值与浮点0</p>
<p>或空指 </p>
<p>针的值相同。 </p>
<p>7.7 只有通过exec函数执行一个程序时,才会分配堆和堆栈。 </p>
<p>7.8 可执行文件包含了用于调试core文件的符号表信息,用strip(1)可以删</p>
<p>除这些 </p>
<p>信息,对两个a.out文件执行这条命令,它们的大小减为98304和16384。
</p>
<p>7.9 没有使用共享库时,可执行文件的大部分都被标准I/O库所占用。
</p>
<p>7.10 这段代码不正确。因为在if语句中定义了自动变量val,所以当if中的</p>
<p>复合语 </p>
<p>句结束时,该变量就不存在了,但是在if语句之外又用指针引用已经不存在</p>
<p>的自动 </p>
<p>变量val。 </p>
<p>第七章 </p>
<p>7.1 原因在于printf的返回值(输出的字符数)变成了main函数的返回码。当</p>
<p>然,并 </p>
<p>不是所有的系统都会出现该情况。 </p>
<p>7.2
当程序处于交互运行方式时,标准输出设备通常处于行缓冲方式,所以</p>
<p>当键入 </p>
<p>新行符时,上次的结果才被真正输出。如果标准输出设备被定向到一个文件而</p>
<p>处于 </p>
<p>完全缓冲方式,则当标准I/O清理操作执行时,结果才真正被输出。
</p>
<p>7.3 由于agrc和argv不象environ一样保存在全局变量中,所以在大多数</p>
<p>Unix系统 </p>
<p>中没有其它办法。 </p>
<p>7.4 当C程序复引用一个空指针出错时,执行该程序的进程将终止,于是可以</p>
<p>利用 </p>
<p>这种方法终止进程。 </p>
<p>7.5 定义如下: </p>
<p>typedef void Exitfunc ( void ) ; </p>
<p>int atexit ( Exitfunc *func ) ; </p>
<p>7.6 calloc将分配的内存空间初始化为0。但是ANSI C并不保证0值与浮点0</p>
<p>或空指 </p>
<p>针的值相同。 </p>
<p>7.7 只有通过exec函数执行一个程序时,才会分配堆和堆栈。 </p>
<p>7.8 可执行文件包含了用于调试core文件的符号表信息,用strip(1)可以删</p>
<p>除这些 </p>
<p>信息,对两个a.out文件执行这条命令,它们的大小减为98304和16384。
</p>
<p>7.9 没有使用共享库时,可执行文件的大部分都被标准I/O库所占用。
</p>
<p>7.10 这段代码不正确。因为在if语句中定义了自动变量val,所以当if中的</p>
<p>复合语 </p>
<p>句结束时,该变量就不存在了,但是在if语句之外又用指针引用已经不存在</p>
<p>的自动 </p>
<p>变量val。 </p>
<p> </p>
<p>第八章 </p>
<p>8.1 用下面几行代替程序8.2中调用printf的语句。 </p>
<p>i = printf ("pid = %d, glob = %d, var = %d\n", getpid( ),</p>
<p>glob, var); </p>
<p>sprintf (buf, "%d\n", i); </p>
<p>write (STDOUT_FILENO, buf, strlen(buf)); </p>
<p>注意要定义变量i和buf。 </p>
<p>这里假设子进程调用exit时只关闭标准I/O流,并不关闭与标准输出相关的文</p>
<p>件描 </p>
<p>述符STDOUT_FILENO。有些版本的标准I/O库会关闭与标准输出相关的文件描</p>
<p>述符从 </p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -