晚上好,
我遇到了分配问题。
基本上我们需要对程序进行编码,该程序将计算给定stdin
的素因子。数据只能通过stdin
进入程序,无论是echo
还是< file.txt
。数据流永远不会超过80个字符(它们可以是数字或不是数字)。
我在程序中使用的函数是read()
,strotol()
和strtok()
,“无关”代码的流程如下:
malloc
分配80个初始字节的内存。 int
存储,通过read()
读取的字符数(我相信,最后\0
)。 realloc()
重新分配内存,以便节省尽可能多的内存(我知道在这种情况下它很简单,但是很好......)。 现在有点棘手:
(n/2)+1
,其中n
是在第2点上方读取的字符数。< / LI>
long
数组,其最大大小为在第nº1点获得的数字。numbers[0]
,结果为:strtol(strtok(line, delim), &end, 10)
。将1
添加到counter
并输入while
循环:
while((numbers[counter] = strtol(strtok(NULL, delim), &end, 10)) != NULL) {
if(!*end) {
// Check whether it's 0, 1, negative, prime or extract its factors
}
else {
fprintf(stderr, "\"%s\" is not a non-negative integer", end)
}
counter++;
}
现在,这里有一些输入及其输出:
输入:echo 1 2 3 4 5 6 7 8 9 10 | ./factors
输出:
1
2
3
2 2
5
2 3
7
2 2 2
3 3
2 5
Segmentation Fault (core dumped).
输入./factors < integers.txt
其中整数包含整数列。
输出:
所有整数都被分解得很好,最后它打印出一个:
Segmentation Fault (core dumped).
输入:echo abc 12 13 14 15 | ./factors
输出:
"abc" is not a non-negative integer
13
2 7
3 5
Segmentation Fault (core dumped).
输入:echo -1 -2 -3 -4 -5 | ./factors
输出:
"-1" is not a non-negative integer
"-2" is not a non-negative integer
"-3" is not a non-negative integer
"-4" is not a non-negative integer
"-5" is not a non-negative integer
输入:echo abc abc abc | ./factors
输出:
"abc" is not a non-negative integer
(并且不继续检查)。
输入:echo 3 4 0 6 7 | ./factors
输出:
3
2 2
(并且不继续检查)。
据我所知,当它遇到0
,非integer
的多个实例或基本上在健康的integer
结束时,它会失败 - 基于数据流。
任何想法我怎么能解决这个问题,为什么它显然随机失败?
我应该让你知道我是C的新手......
非常感谢您的进步。
=============================================== =====
EDIT1:根据请求,以下是生成numbers[]
并从stdin
读取的代码片段:
char *line;
char *end;
char *delim = " \n";
int charsread, counter;
line = malloc(80);
charsread = read(0, line, 81);
if (charsread == 0) {
return EX_OK;
}
realloc(line, charsread);
maxelem = (charsread / 2) + 1;
long numbers[maxelem];
numbers[0] = strtol(strtok(line, delim), &end, 10);
if (!*end) {
zeroone(numbers[0]);
}
else {
fprintf(stderr, "\"%s\" is not a non-negative integer\n", end);
}
counter = 1;
while [...]
答案 0 :(得分:2)
尝试使用gdb调试segfault,通过设置适当的环境变量使其在segfaulting时转储核心,或者直接在gdb中运行它。 Segfault意味着您正在读/写一部分不应该的内存。随机性意味着你可能正在粉碎堆栈或其他东西。我认为“printf”应该受到指责,检查他们的论点。您也没有检查数字是否小于数组长度?它可能会超支吗?
答案 1 :(得分:1)
好的,让我们回顾一下我们在那里的一些事情,看看我们是否能解决你的问题。
您的计划不需要这样做:
realloc(line, charsread);
尝试减少内存占用是正确的,但是如果你分配的太多,那么呢?这是80个字节。不要过分复杂,你的盘子已经足够了。
这很奇怪:
maxelem = (charsread / 2) + 1;
long numbers[maxelem];
这很好,可以在您的情况下使用,但您可以通过计算数字组来更准确地确定元素的数量。
我建议尝试在lopp中完成整个提取
关于实际的segmentation fault
...我可能错了,因为我没有机会在我的机器上重现这一点,但我认为错误的发生是因为你没有终止你的line
具有\0
字符。在C中,因为我确定你已经知道你发布的片段的外观,行通常是我们所谓的“以NULL结尾”,所以按照惯例,我们用值0来终止它们,这是0的值。 NUL
字符,也表示为\0
(有时候有点令人困惑,因为人们会在“NULL-terminated”,“NUL”字符和“NULL指针”之间混淆,另一件事。)
这会使你的程序中断,因为最终你的程序试图用strtok
读取行的结尾,但它不知道在哪里停止。它没有缓冲区长度的良心以及在此缓冲区中停止的位置。所以它不断读取,到达不允许访问的内存地址,因此出现segmentation fault
。
所以你想简单地说:
/*
** If you keep your realloc, you need to allocate for the number of read
** characters from stdin, and for an extra char to terminate.
*/
line = realloc(line, charsread + 1);
/*
** Terminate the string.
*/
line[charsread] = '\0';
更新:啊,你实际上差不多了,你有逻辑,但可能只是错过了这一点......你甚至自己写了这个:
在int中存储,通过read()读取的字符数(我相信,最后的\ 0)。
部分正确。如果您确实获得了80个字符的行,那么您的read
调用将返回最后一行\0
的行。但是大部分时间你都没有,所以你的读缓冲区只能读取可见字符,你需要自己对字符串进行空终止。
我还会尝试重写你的处理循环,以便对strtok进行第一次初始调用。写入并不总是很方便,但通常看到一个代码块几乎与循环内部或循环之后的内部相同,这让我觉得有更好的逻辑方法。
答案 2 :(得分:0)
非常感谢您的深刻回应。
最后我只重写了整个事情,因为它看起来并不像我预期的那么干净。
由于strtok
的手册指定了NULL
的返回值,如果无法提取令牌,这就是我最终的结果:
long number;
item = strtok(line, delim);
while (item != NULL) {
number = strtol(item, &rest, 10);
if (*rest == 0) {
zeroOne(number);
}
else {
fprintf(stderr, "\"%s\": not a non-negative int.\n", item);
}
item = strtok(NULL, delim);
}
似乎是一种更清晰的方法,并且在尝试进入之前的NULL
循环之前,确实会考虑返回strtok返回的值while
的事实。然后,今天早上我回到这里阅读你的回复:)
关于您对该行的\0
的硬编码输入的后续问题:这是否意味着我的上一个strtok
实际输出\0
令牌并尝试输入循环,还是在我最后一个引入的角色后到达实体时返回NULL
?
作为惯例,当使用read()
(或者可能是其他读取函数,例如fgets()
时,我应该总是尝试将\0
硬编码到读取行以允许其他函数检查{ {1}} / EOL
?
如果其他人在使用上述任何功能时遇到问题(EOF
和strtok
),我建议您查看本网站上发布的这两个问题:
关于strtol
的第二个论点:Strtol second argument
关于strtol
的输出:Cannot concatenate strtok's output variable. strcat and strtok