您的直接分段错误是由于:
char *temp;
...
fscanf(stdin, "%s", temp)
其中temp 是一个未分配 字符指针。当你声明一个指针时,例如char *temp; 指针没有指向 任何东西。它只是一个空变量。对于一个指向你希望temp 工作的指针,它必须将地址保存到一个足够大小的内存块作为它的值。
这样想。当您声明 int i; 时,您不希望 i 保留任何特定值,直到您为其分配值。 'i' 未初始化。指针也不例外。在您为其分配有效地址之前,您不会期望 char *temp; 指向任何东西。当您调用fscanf 并尝试将输入存储在temp - boom 指向的地址时,会出现段错误,因为不知道temp 到底指向哪里。这肯定不是分配到足够大小的内存块。
除了直接的问题之外,很难遵循代码的逻辑,因为它的推理非常混乱。猜猜看,您的目标似乎是从命令行传递x 的值,然后最终将size 的该值用于expand 'size' 从stdin 读取的字数。相反,看起来您已经下注并刚刚分配了 size = 3; 并决定尝试让它为 3 个单词工作。不用放弃,做对了就不费力了。
当您将作为字符串输入的数字作为argv[1] 转换为整数时,您可以使用该值创建一个包含那么多指针的可变长度数组。没有任何令人信服的理由来声明任意数量的指针,因为您输入的输入可能会告诉您要扩展多少字。此时也不需要为指针分配存储空间,因为这似乎是expand 的目的。
您正在从标准输入读取 单词。只要它们是普通单词,您就可以简单地使用静态声明的缓冲区来保存从stdin 读取的单词。只要它们是字典中的单词,您就知道它们不会超过28-characters。因此,您只需要 29-characters(+1 表示 nul-terminating 字符)即可在阅读时保存每个单词。[1]
scanf 系列函数根据给定的格式字符串返回成功转换的次数。您不使用feof 来查找输入的结尾,而是检查fscanf 的返回并将您处理的字数限制为size。要清理您处理输入的方式(我已将 size 用于您的 x),您可以执行类似于以下的操作:
enum { MAXC = 32 }; /* constant for static buffer - longest word 28 char */
...
int main (int argc, char **argv) {
...
int size; /* validate numeric input */
if ((size = isdigit (*argv[1]) ? atoi (argv[1]) : 0) <= 0) {
fprintf (stderr, "error: invalid input. usage %s int > 0\n", argv[0]);
return 1;
}
...
int count = 0, i = 0;
char *words[size]; /* array of 'size' pointers to char */
char temp[MAXC] = {0}; /* buffer to hold each word input */
/* read at most 'size' words from stdin */
while (size-- && fscanf (stdin, "%s", temp) == 1)
words[count++] = expand (temp, strlen (temp)); /* expand */
查看声明的每个部分并阅读循环。 (在设置size 时了解三元 运算符的使用——在许多情况下它是一个有用的快捷方式)请注意您如何有两个条件来读取size > 0 和fscanf (stdin, "%s", temp) == 1。如果您读取了size 或没有其他输入要读取,则循环终止。
清理的其余部分相当简单。但是请注意,不需要使用可变参数 fprintf 来简单地将换行符打印到 stderr(例如 fprintf (stderr, "\n");)。只需打印单个字符(例如fputc ('\n', stderr);)。
此外,在您分配内存时,您 (1) 保留一个指向内存块开头的指针,以便它可以(2) 在不再需要时释放。始终,始终在 Linux 上使用像 valgrind 这样的内存/错误检查程序来验证您是否正确使用了内存,并且在不再需要时所有块都已被释放。每个操作系统都有类似的程序,并且它们易于使用。没有理由不这样做。
将所有部分放在一起,您可以执行以下操作:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
enum { MAXC = 32 }; /* constant for static buffer - longest word 28 char */
char *expand (char *source, size_t size);
int main (int argc, char **argv) {
if (argc != 2) { /* validate number of arguments */
fprintf (stderr, "error: insufficient input.\n");
return 1;
}
int size; /* validate numeric input */
if ((size = isdigit (*argv[1]) ? atoi (argv[1]) : 0) <= 0) {
fprintf (stderr, "error: invalid input. usage %s int > 0\n", argv[0]);
return 1;
}
int count = 0, i = 0;
char *words[size]; /* array of 'size' pointers to char */
char temp[MAXC] = {0}; /* buffer to hold each word input */
/* read at most 'size' words from stdin */
while (size-- && fscanf (stdin, "%s", temp) == 1)
words[count++] = expand (temp, strlen (temp)); /* expand */
for (i = 0; i < count; i++) { /* output each string read */
char *fmt = i ? ", %s" : "%s";
fprintf (stderr, fmt, words[i]);
}
fputc ('\n', stderr);
for (i = 0; i < count; i++) /* free allocated memory */
free (words[i]);
return 0;
}
char *expand (char *source, size_t size)
{
char *expansion = calloc (1, size * sizeof *expansion + 1);
size_t i;
if (!expansion) { /* validate memory allocation */
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
for (i = 0; i < size; i++)
expansion[i] = source[i];
return expansion;
}
(注意:calloc 在上面使用是为了避免 valgrind 的某些版本中的怪癖。根据版本的不同,它可能会抱怨在 if(..) 语句中未初始化使用 expansion。这不是一个错误,但在旧版本中是一个怪癖。为确保您没有遇到该问题,我使用calloc 而不是malloc,它将所有新内存初始化为零并避免警告。注意: 它还确保了 nul-termination 的 expansion 没有明确的 expansion[size] = 0; 在循环之后。)
示例输入
$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
输出
$ ./bin/expansion 5 < ../dat/captnjack.txt
This, is, a, tale, Of
$ ./bin/expansion 4 < ../dat/captnjack.txt
This, is, a, tale
内存/错误检查
$ valgrind ./bin/expansion 5 < ../dat/captnjack.txt
==12849== Memcheck, a memory error detector
==12849== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==12849== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==12849== Command: ./bin/expansion 5
==12849==
This, is, a, tale, Of
==12849==
==12849== HEAP SUMMARY:
==12849== in use at exit: 0 bytes in 0 blocks
==12849== total heap usage: 5 allocs, 5 frees, 18 bytes allocated
==12849==
==12849== All heap blocks were freed -- no leaks are possible
==12849==
==12849== For counts of detected and suppressed errors, rerun with: -v
==12849== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
如果您有任何问题,请告诉我。我试图尽可能地猜测你的代码要去哪里。如果我错过了标记,请告诉我,我很乐意提供进一步的帮助。
脚注 1. - 'Antidisestablishmentarianism' 是未删节词典中最长的词。