C和指针的新手,我无法弄清楚为什么我在这里有分段错误...这里的一些代码未使用,我只是想测试我的单词是否有用正在正确读取并分配正确的空间量。最终我会有一个char **,其中打印的格式看起来像" cat the"," new hey",.....
在我的代码中,单词代表每个单词
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<ctype.h>
char *expand(char* source, int size);
char *expand(char *source, int size)
{
char *expansion = (char *)malloc(size * sizeof(char));
int i;
for (i=0; i<size-1; i++)
{
expansion[i] = source[i];
}
free(source);
return expansion;
}
int main(int argc, char **argv)
{
int x;
if (argc <= 2)
{
if (isdigit(*argv[1]))
{
x = atoi(argv[1]);
}
}
else
{
fprintf(stderr, "Invalid Input\n");
return 1;
}
//store pointers to each individual word
char *words = (char *)malloc(3 * sizeof(char));
int size = 3;//initial arbitrary size
int count = 0;
char *temp;
while (1)
{
fscanf(stdin, "%s", temp);
if (feof(stdin))
{
break; //break if end of file
}
if (count == size - 1)
{
size++;
words = expand(words, size);
}
words[count] = *temp;
count++;
}
int i;
for(i=0; i<size-1; i++)
{
fprintf(stderr, "%s, ", words[i]);
}
fprintf(stderr, "\n");
return 0;
}
答案 0 :(得分:2)
你跳出来的麻烦的一个主要原因是你声明char *temp
;然后,在你的while循环中,开始尝试将数据读入指针所指向的内存中...但是,你从不打扰实际分配内存并将指针指向它。
这是一个非常理想的示例,您应该使用它来修改char *words
和char *temp
。我建议,在您熟悉如何正确管理动态内存(malloc / free)之前,请先从静态声明开始:
char words[512];
int size = 3;
int count = 0;
char temp[512];
words[0] = 0;
temp [0] = 0;
while...
同时&#34;幻数&#34;这样的声明显然不明智或安全,它们使用一个数字(如512)创建一个起始点,该数字可能比您在测试时可能传递的任何基于行的输入更大。一旦你正常工作,然后再回来看看malloc
!
考虑这个为argv[1]
传递的理论参数分配内存的例子:
char *ptr = NULL;
ptr = malloc(strlen(argv[1] + 1);
strcpy(ptr, argv[1]);
... Do lots of stuff ...
free(ptr);
请注意,分配的大小超过了为字符串的空终止符留出空间所需的字符串长度。
您可能感兴趣的还有strdup
功能,它会为您执行正确的分配,但是当您通过时,您仍然必须记住free
内存。
答案 1 :(得分:1)
您的即时分段错误原因是:
char *temp;
...
fscanf(stdin, "%s", temp)
其中temp
是未分配的字符指针。声明指针时,例如char *temp;
指针不会指向任何东西。它只是一个空变量。对于指向您希望temp
起作用的函数的指针,它必须将地址保存为一个足够大小的内存块作为其值。
这样想。当您声明int i;
时,在您为其指定值之前,不要期望i
保留任何特定值。 'i'
未初始化。指针也不例外。在您为其分配有效地址之前,您不会指望char *temp;
指向任何内容。当您致电fscanf
并尝试将输入存储在temp
- 热潮所指向的地址时,会发生段错误,因为无法确切地说明temp
指着。它当然不是一个足够大小的分配内存块。
除了当前的问题之外,很难遵循代码的逻辑,因为它在推理中非常混乱。猜测,您的目标似乎是从命令行传递x
的值,然后最终将size
的值用于expand
'size'
从中读取的单词数量stdin
。相反,它看起来像你被抨击并且刚刚分配size = 3;
并且决定尝试让它为3个单词工作。没有必要放弃,正确地做,不需要更多的努力。
将作为字符串输入的数字argv[1]
转换为整数时,可以使用该值创建多个指针的可变长度数组。没有任何令人信服的理由来声明一些任意数量的指针,因为你所做的输入可能会告诉你你希望扩展多少个单词。此时也无需为指针分配存储空间,因为这似乎是expand
的目的。
您正在从标准输入读取单词。只要它们是普通单词,您就可以简单地使用静态声明的缓冲区来保存从stdin
读取的单词。只要它们是字典中的单词,您就知道它们不会超过28-characters
。因此,对于 nul-terminatedating 字符,您只需要29-characters
(+1
)即可将每个单词保留为读取它。 [1]
scanf
系列函数根据给定的 format-string 返回成功转换的次数。您不使用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
和{{提供2个条件1}}。如果您阅读fscanf (stdin, "%s", temp) == 1
或没有其他要读取的输入,则循环终止。
清理的其余部分相当直接。但请注意,不需要使用可变参数size
来简单地将换行符打印到fprintf
(例如stderr
)。只需打印单个字符(例如fprintf (stderr, "\n");
)。
此外,无论何时分配内存,都你 (1)保留指向内存块开头的指针,因此它可以(2)在不再需要时释放。始终,始终在Linux上使用像fputc ('\n', stderr);
这样的内存/错误检查程序来验证您是否正确使用了内存,并且在不再需要时已释放所有块。每个操作系统都有类似的程序,它们易于使用。没有理由不去。
将所有部分组合在一起,您可以执行以下操作:
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
中未expansion
的未初始化使用这不是一个错误,但在旧版本中是一个怪癖。为了确保你没有遇到这个问题,我使用if(..)
而不是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
如果您有任何疑问,请与我们联系。我试着尽可能地猜测你在哪里使用你的代码。如果我错过了标记,请告诉我,我很乐意进一步帮助。
脚注1。 - &#39; Antidisestablishmentarianism &#39;是未删节字典中最长的单词。