打印数组时,我无法摆脱多余的字符。我不确定我做错了什么。输出将随机字符添加到行尾。任何帮助深表感谢。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv){
int i=0;
char c;
const char * ch;
int num_lines = 0;
int k = 0;
FILE *fpin;
if(argc > 1){
fpin = fopen(argv[1], "r");
}
if (fpin == NULL){
printf("Cannot Open File");
return(0);
}
while(!feof(fpin)){
c = getc(fpin);
if(c == '\n'){
num_lines++;
}
}
printf("%d", num_lines);
char **result = malloc(sizeof(char) * num_lines + 2);
for(i=0;i<=num_lines;i++){
result[i] = malloc(1000*sizeof(char));
}
i=0;
rewind(fpin);
while(i<num_lines){
c = getc(fpin);
ch = &c;
printf("%c", c);
if (c == '\n'){
strncat(result[i], "\0", 1);
i++;
}
if(result[i] == NULL){
printf("bad memory");
break;
} else {
strncat(result[i], ch, sizeof(char));
}
}
for(i=0;i<=num_lines;i++){
printf("%s", result[i]);
}
}
答案 0 :(得分:1)
这条线路不对。
char **result = malloc(sizeof(char) * num_lines + 2);
应该是:
char **result = malloc(sizeof(char*) * num_lines + 2);
请记住,您正在尝试分配num_lines
char*
,而不是num_lines
char
。我不确定你为什么要在那里增加+ 2
。你只需要:
char **result = malloc(sizeof(char*) * num_lines);
for(i=0;i<num_lines;i++){ /* Note the use of < and not <= */
result[i] = malloc(1000*sizeof(char));
}
您可以进一步将for
循环简化为:
for(i=0;i<num_lines;i++){
result[i] = malloc(1000); /* sizeof(char) is always 1 */
}
答案 1 :(得分:1)
其他答案指出了大部分主要问题,而@David C. Rankin在评论中提到了一个关键点:
调用strncat时,结果[i]不会终止。因此,strncat不知道在哪里放。
总结:
char **result = malloc(sizeof(char *) * (num_lines + 1)); // Proper allocation
for(i = 0; i <= num_lines; i++)
{
result[i] = calloc(1000, sizeof(char));
}
我要添加的最后一点是在重建时跳过将换行符附加到行上:
while(i <= num_lines)
{
// ...
if(c == '\n')
{
i++;
}
else if(result[i] == NULL) // <== Note the else
{
// bad memory, I guess?
}
else
{
strncat(result[i], ch, 1);
}
}
然后在打印时将其添加回来:
print("%s\n", result[i]);
答案 2 :(得分:0)
以下内存分配方式会导致segmentation fault
。
char **result = malloc(sizeof(char) * num_lines + 2); //Instead of sizeof(char) you should use sizeof(char *).
for(i=0;i<num_lines;i++){
result[i] = malloc(1000*sizeof(char));
}
而不是尝试以下 -
char **result = malloc(sizeof(char *) * num_lines);
for(i=0;i<num_lines;i++){
result[i] = malloc(1000*sizeof(char));
}
然后程序的剩余部分工作正常。无需改变任何东西。
但是当你动态分配内存时,不要忘记最后释放内存。
for(i=0;i<num_lines;i++){
printf("%s", result[i]);
}
free(result); // It frees the allocated memory
[注意]:当您使用命令行参数时,您应检查用户的输入,如果未提供必要的输入,则需要打印使用消息。否则会导致Segmentation fault
if(argc!=2){
printf("Usage: ./a.out Filename\n");
return 0;
}
答案 3 :(得分:0)
因此,strncat(dst, src, n)
扫描dst
寻找'\0'
,然后从n
添加最多src
个字符,停止在'\0'
终止},然后追加'\0'
。正如其他地方所述,你的问题是你没有初始化每个result[i]
是一个空字符串...... calloc()
会为你做的,虽然有一点点过度杀戮。
除此之外:了解C确实没有字符串类型非常重要。它具有的是字符值数组,以及字符值'\0'
是“字符串终止符”的约定。使用此约定,strxxx()
函数在char数组上执行有用的“字符串式”操作......但是当您使用它们时,值得记住“没有字符串”。 (有很深的魔力允许指针和数组非常接近,但不完全是彼此的双重。这使得char*
看起来更像是一个“字符串”,但它只是一种幻觉,无论多么方便有用的可能是......这里有薄冰,如果你不小心,你就会遇到麻烦。)
现在,对于每个字符读取,您的代码都会执行strncat()
,它将重新扫描当前result[i]
...寻找'\0'
,我在这里告诉你是O(n ^ 2):-((除非一些聪明的代码缓存了最后的已知长度。)
此外,对于超过1000个字符的行(包括其终止'\0'
),您将超出result[i]
的结尾。
除此之外: C给人类最大的礼物就是你可以轻松地覆盖一系列的char :-(每次你触摸一个“字符串”时你都需要问自己“这可以吗?”超支?“,然后当你认为你有答案时,再问一遍”这可能会超出考虑到最后的'\0'
- 并且集中精力于“字符串”的长度之间的差异(其中不包括'\0'
)和char数组的长度(确实如此)。
此外,如果输入中出现'\0'
,那么(有效地)会切断线的其余部分。当然,你可能有理由相信这种情况永远不会发生。 (当不可能的事情发生时,很多代码已经崩溃并烧毁了!)
正如其他地方所述,你计算'\n'
的数量,并且(排序)加1来给你行数,除非文件以'\n'
结尾,否则这很好。您可以检查扫描循环中读取的最后一个字符是否为'\n'
,以判断您是否有一个尾随的,未终止的行。
这是另一个教训......集中(努力)处理边缘情况和循环终止条件......你的读取循环是:
while(i<num_lines){
....
if (c == '\n'){
....
i++;
}
....
}
因此,由于num_lines
实际上是'\n'
的数量,因此不会读取尾随(未'\n'
行)(如果有的话)。
另一方面,您的输出循环具有微妙的不同终止条件:
for(i=0;i<=num_lines;i++){
printf("%s", result[i]);
}
如果result[num_lines]
已被初始化为空,那将会很好!
对于读取循环,您可以:
l = 0 ;
i = 0 ;
while (!feof(fpin)) {
c = getc(fpin);
if (c == '\n') {
result[i][l] = '\0' ;
i += 1 ;
l = 0 ;
}
else if ((c != '\0') && (l < (1000 - 1))) {
result[i][l] = c ;
l += 1 ;
}
}
if (l != 0)
num_lines += 1 ;
请注意,最后l == 0
表示文件以'\n'
结尾(可能后跟任意数量的'\0'
),相反l != 0
表示存在not-empty尾随行未被'\n'
终止(忽略任何'\0'
)。这可能很有用 - 虽然不是在你的情况下,在任何情况下你输出的结果都少于'\n'
。
这会忽略输入中的'\0'
并将行截断为999个字符。你可能想要做一些事情来更彻底地处理这些案件。