C和C++安全编码(原书第2版)
上QQ阅读APP看书,第一时间看更新

2.5.4 动态分配函数

ISO/IEC TR 24731-2描述了来自POSIX的getline()函数。getline()函数的行为与fgets()类似,但提供了一些额外的功能。首先,如果输入行过长,那么该函数使用realloc()调整缓冲区的大小,而不是截断输入。其次,如果它执行成功,则返回读取的字符数,这对于确定在输入的换行符之前是否有任何空字符是非常有用的。getline()函数仅适用于使用malloc()分配的缓冲区。如果传入一个空指针,则函数getline()会分配一个大小足够容纳输入的缓冲区。因此,随后用户必须明确地用free()释放该缓冲区。当分隔符等于换行符时,getline()函数相当于getdelim()函数(getdelim()函数也在ISO/IEC TR 24731-2中定义)。例2.12中所示的程序片段使用getline()函数从stdin中读取一行文本。

例2.12 使用函数getline()从stdin中读入


01  int ch;
02  char *p;
03  size_t buffer_size = 10;
04  char *buffer = malloc(buffer_size);
05  ssize_t size;
06
07  if ((size = getline(&buffer, &buffer_size, stdin)) == -1) {
08    /* 
处理错误 */
09  } else {
10    p = strchr(buffer, '\n');
11    if (p) {
12      *p = '\0';
13    } else {
14      /* 
未找到换行符, 
刷新标准输入至行尾 */
15      while (((ch = getchar()) != '\n')
16         && !feof(stdin)
17         && !ferror(stdin)
18         );
19    }
20  }
21
22  /* ... 
对缓冲区进行处理 ... */
23
24  free(buffer);

getline()函数返回写入缓冲区的字符数目,包括换行符,如果在文件结束前遇到它。如果发生读取错误,流中的错误标记就被设置,函数getline()返回–1。因此,此函数的设计违反《C安全编码标准》[Seacord 2008],“ERR 02-C.避免带内错误标志”,因为ssize_t类型是以提供带内错误标志为目的而被创建的。

注意,此代码也没有检查malloc()是否执行成功。然而,如果malloc()失败,它返回NULL,这被传递给getline()函数,getline()函数将及时地分配它自己的一个缓冲区。

表2.4总结了本节中描述的gets()的一些替代函数。所有这些函数都可以安全地使用。

表2.4 gets()的替代函数