随便看看代码表明:
您必须使用strcpy()
或主题的变体将找到的字符串复制strtok()
到姓氏等中。
你写它的方式,你扔掉你分配的内存。
您会得到重复的输出,因为您正在存储指向用于在surname
andfirst
数组中保存行的字符串的指针。当您进行打印时,该字符串仅包含最后一行。这一点和前一点是第一点的推论。
您只需为中间的首字母分配一个字符。然后,您strcat()
可以将它们视为字符串。我建议将中间名首字母视为字符串,就像其他名称一样。或者,由于您不需要打印它们,您可能决定完全忽略中间的首字母。
使用 17 代替enum { NAME_LENGTH = 17 };
或等效不是一个好主意。
毫无疑问,还有其他问题。
我猜你在学习过程中还没有达到结构。如果您已经介绍了结构,您可能应该使用结构类型来表示完整的名称,并使用单个名称数组而不是并行数组。这也可能会简化内存管理;您将在结构中使用固定大小的数组元素,因此您只需为每个名称进行一次分配。
下面的代码产生输出:
Ryan Elizabeth
McIntyre O
Cauble-Chantrenne Kristin
Larson Lois
Thorpe Trinity
Ruiz Pedro
在这段代码中,该err_exit()
函数非常有价值,因为它将错误报告变成了单行调用,而不是 4 行段落,这意味着您更有可能进行错误检查。它是变长参数列表的基本用法,你可能还不明白,但它非常方便和强大。唯一可以进行错误检查但不是的函数是fclose()
and printf()
。如果您正在阅读文件,则检查没有什么好处fclose()
;如果您正在编写并且fclose()
失败,您可能已经用完了磁盘空间或类似的东西,并且报告错误可能是合适的。您可以添加<errno.h>
到标题列表并报告errno
和strerror(errno)
如果您想进一步改进错误报告。代码释放分配的内存;valgrind
给它一个干净的健康账单。
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void err_exit(const char *fmt, ...);
int main(void)
{
enum { NAME_SIZE = 25 };
const char *file = "names1.txt";
int size, i;
char **surname, **first, str[80];
FILE *fp_input = fopen(file, "r");
if (fp_input == NULL)
err_exit("Failed to open file %s\n", file);
if (fgets(str, sizeof(str), fp_input) == 0)
err_exit("Unexpected EOF on file %s\n", file);
if (sscanf(str, "%d", &size) != 1)
err_exit("Did not find integer in line: %s\n", str);
if (size <= 0 || size > 1000)
err_exit("Integer %d out of range 1..1000\n", size);
if ((surname = (char**)malloc(size * sizeof(char*))) == 0 ||
(first = (char**)malloc(size * sizeof(char*))) == 0)
err_exit("Memory allocation failure\n");
for (i = 0; i < size; i++)
{
if ((surname[i] = (char*)malloc(NAME_SIZE * sizeof(char))) == 0 ||
(first[i] = (char*)malloc(NAME_SIZE * sizeof(char))) == 0)
err_exit("Memory allocation failure\n");
}
for (i = 0; i < size && fgets(str, sizeof(str), fp_input) != NULL; i++)
{
char *tok_s = strtok(str, ",. \n");
char *tok_f = strtok(NULL, ". ");
if (tok_s == 0 || tok_f == 0)
err_exit("Failed to read surname and first name from: %s\n", str);
if (strlen(tok_s) >= NAME_SIZE || strlen(tok_f) >= NAME_SIZE)
err_exit("Name(s) %s and %s are too long (max %d)\n", tok_s, tok_f, NAME_SIZE-1);
strcpy(surname[i], tok_s);
strcpy(first[i], tok_f);
}
if (i != size)
err_exit("Only read %d names\n", i);
fclose(fp_input);
/* prints arrays */
for (i = 0; i < size; i++)
printf("%s %s\n", surname[i], first[i]);
for (i = 0; i < size; i++)
{
free(surname[i]);
free(first[i]);
}
free(surname);
free(first);
return 0;
}
static void err_exit(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(1);
}