2009-12-03 72 views
1

我有一个文本文件,最多可以有100个IP地址,每行1个。我需要将每个地址作为一个字符串读入一个名为“list”的数组中。首先,我假设“列表”需要是一个二维字符数组。每个IP地址的长度为11个字符,12,如果你有“\ 0”,所以我宣布名单如下:如何在C中逐行读取文件?

char list[100][12];

接下来,我试图用fgets来读取数据流:

for (i = 0; i < 100; i++) 
    { 
     if (feof(stream)) 
      break; 
      for (j = 0; j < 12; j++) 
      fgets(&list[i][j], 12, stream); 
     count++; 
    } 

要检查,看看是否丝线正确读取,我试图将他们输出:

for (i = 0; i < 5; i++) 
    { 
     for (j = 0; j < 11; j++) 
      printf("%c", list[i][j]); 
     printf("\n"); 
    } 

运行程序后,很清楚什么是错的。作为初学者,我不确定是什么,但我猜我正在读错文件。没有错误。它编译,但在两行打印一个奇怪的地址。

编辑:

我替换此与fgets代码:

for (i = 0; i < 100; i++) 
    { 
     if (feof(stream)) 
      break; 
     fgets(list[i], 12, stream); 
     count++; 
    } 

现在打印五根弦,但他们是从内存中 “随机” 的字符。

+0

任何错误信息? – Nifle 2009-12-03 19:44:46

+1

您是否尝试启动调试器?如果通过查看源代码无法弄清楚发生了什么问题,这应该始终是您的第一步。 – 2009-12-03 19:45:28

+0

你说“......很明显有什么不对。”但你不会说这是什么错误。没有这个,很难说更多。 是否有错误?有没有输出,但不是你所期望的? – FrustratedWithFormsDesigner 2009-12-03 19:47:13

回答

6

首先,阅读:

 for (j = 0; j < 12; j++) 
     fgets(&list[i][j], 12, stream); 

你有一个很大的问题就在这里。这是试图读取字符串到您阵列中的每个连续的字符

总而言之,我认为你会让这件事情比需要的复杂得多。把你的数组想象成100个字符串,并且fgets将一次处理一个字符串。这意味着阅读可以是这个样子:

for (i=0; i<100 && fgets(list[i], 11, string); i++) 
    ; 

还有另外一个小细节处理:fgets()通常保持在每行的末尾新行。因此,您可能需要为13个字符留出空间(地址11,新行1,NUL终止符1),否则您可能需要将数据读入临时缓冲区,并将其仅复制到您的list在你剥离新线之后。

在当前用于打印字符串的代码中,您一次只能处理一个字符,这可以起作用,但不必要的困难。有几个人建议使用%s printf转换,这本身就很好。但是,要使用它,你必须简化索引。打印第6个地址会是这个样子:

for (i=0; i<6; i++) 
    printf("%s", list[i]); 
+0

谢谢,你的代码有效;但是,打印时,由于某种原因,仅打印前三个地址。 – 2009-12-03 20:15:11

+0

我将缓冲区扩展到13,现在可以工作。 – 2009-12-03 20:16:44

+0

@ ttread31:是的,由于太短的缓冲区,每个地址都会被分为两部分,所以前六个“项目”实际上只有三个地址。 – 2009-12-03 22:29:32

4

您对fgets的呼叫最多可以从串流中读取11个字符。所以你不想为每个字符串的每个字符调用一次。考虑一下这些循环:在i = 0和j = 0的情况下,它可以读取多达11个字符到&list[0][0]。然后在i = 0和j = 1的情况下,它读取另外11个字符到&list[0][1]。这是错误的,原因有两个 - 它覆盖最后一次调用的结果,并且可能会写入比列表[0]更多的字节。

+0

fgets是否不是逐行而是通过文件中的字符? – 2009-12-03 19:48:15

+0

是的,次循环是不必要的,因为你每次读12个字符时读到fgets – 2009-12-03 19:48:49

+0

这似乎是一个逻辑问题。 – Ismael 2009-12-03 19:49:11

1

一个换行符使得与fgets停止阅读,但它被认为是一种有效的字符,因此它是包含复制到str中的字符串中。

您可能正在读取第一个调用fgets中的前12个字符,然后第二个调用将捕获换行符,然后第三个调用将获得下一行。

尝试使用与fgets有15个字符的限制,扩大你的缓冲区。

1

第二个循环是没有必要的,它会损坏你的记忆。你应该做这样的事情,

for (i = 0; i < 100; i++) 
{ 
if (feof(stream)) 
break; 
fgets(&list[i][j], 12, stream); 
count++; 
} 

To check to see if the strings were read properly, I attempt to output them: 

for (i = 0; i < 5; i++) 
{ 
printf("%s\n", list[i]); 
} 
1

为(i = 0;我< 100;我++){

if (feof(fp)) 
     break; 

    fscanf(fp,"%s\n",list[i]); 

}

1

不要使用feof()为您的循环条件;直到你试图读取文件末尾之后才会返回true,这意味着你的循环执行的次数太多了。检查您输入调用的结果(无论您使用fgets()fscanf()),看看它是否成功,然后检查如果feof()你有一个错误的条件。

if (fgets(buffer, sizeof buffer, stream) != NULL) 
{ 
    // process the input buffer 
} 
else if (feof(stream) 
{ 
    // handle end of file 
} 
else 
{ 
    // handle read error other than EOF 
} 

fgets()读取整个字符串,而不是单个字符,所以你不希望传递的每个个性的地址在您的字符串。说它像这样代替:

if (fgets(list[i], sizeof list[i], stream) != NULL) 
{ 
    // process input address 
} 

而现在,对于波特的关于数组和指针通常的高谈阔论......

当数组表达式出现在大多数情况下,表达的类型隐式转换而来“的T N元件阵列”到‘指针T’,和表达式的值是数组的第一元素的地址。此规则的例外是当阵列表达是sizeof&运营商的操作数,或它是一个字符串文字正被用作在声明的初始化。当你听到人们说“数组和指针是同一件事”时,他们正在篡改这条规则。数组和指针是完全不同的动物,但它们可以在某些情况下互换使用。

请注意,在上面的代码中,我通过了list[i]作为没有任何装饰的fgets()的第一个参数(例如&运算符)。即使的list[i]类型是“炭的12个元素的数组”,在这种情况下它是隐式转换为类型“字符指针”,并且该值将是list[i][0]地址。请注意,我也将相同的表达式传递给sizeof运算符。在这种情况下,数组表达式的类型是而不是转换为指针类型,并且sizeof运算符返回数组类型(12)中的字节数。

只是钉了下去:

 
Expression  Type    Implicitly converted to 
----------  ----    ---- 
list   char [100][12] char (*)[12] (pointer to 12-element array of char) 
list[i]   char [12]  char * 
list[i][j]  char    N/A 

这一切都意味着,fgets()将读取到下一个12个字符(只要不打新行或EOF第一),并将其存储在开始list[i][0]。请注意,fgets()将在您的字符串末尾写入一个终止nul字符(0)。另请注意,如果fgets()遇到换行目标阵列中有空间,并且终止nul,fgets()将在nul字符之前存储终止换行符。所以,如果你输入的文件有一个像

1.1.1.1\n 

线,在读取后您的输入缓冲区的内容将是"1.1.1.1\n\0xxx"其中x是一些随机值。如果你不想换行那里,你可以使用strchr()功能找到它,然后用0覆盖它:

char *newline; 
... 
if ((newline = strchr(input[i], '\n')) != NULL) 
{ 
    *newline = 0; 
} 

因为在接下来的换行符fgets()停止,因为你的输入缓冲区的大小为12个字符,您可能会遇到这样的情况:您将新行作为文件中的下一个输入字符;在这种情况下,fgets()将只写入新行到输入缓冲区,所以你会有一些空的条目,这可能不是你想要的。您可能需要在输入缓冲区中添加一个额外的字节以避免这种情况。

全部放在一起:

char list[100][13]; 
... 
for (i = 0; i < 100; ++) 
{ 
    if (fgets(list[i], sizeof list[i], stream) != NULL) 
    { 
    char *newline = strchr(list[i], '\n'); 
    if (newline != NULL) 
     *newline = 0; 
    printf("Read address \"%s\"\n", list[i]); 
    count++; 
    } 
    else if (feof(stream)) 
    { 
    printf("Reached end of file\n"); 
    break; 
    } 
    else 
    { 
    printf("Read error on input; aborting read loop\n"); 
    break; 
    } 
}