您面临的最大挑战是为工作选择正确的工具。您还必须将您的结构声明与您拥有的数据更好地匹配。
虽然scanf 是一个很好的工具,但当您需要阅读不同的输入行时,它就不是适合这项工作的工具了。在您的数据中,您有blank lines 和varying number of fields 每行可供阅读。与其尝试 shoehorn 一系列测试和格式化字符串以便 scanf 可以工作,正确的方法是从文件中读取整行数据,然后解析该数据以获得所需的信息.
面向行输入的合适工具是fgets 和getline。在这种情况下,我更喜欢getline,因为它返回它在每行中读取的实际字符数,从而可以对空行/短行进行简单测试。
一旦您读取了一行数据,适合这项工作的工具是strtok 或strsep。您还可以使用简单的指针手动解析数据行。无论如何,您解析数据并将分离的值分配给您的结构。
我已在下面注释掉了您的部分代码,以便您可以跟进更改。一些简单的风格,其余的实现我上面描述的。请注意,有很多方法可以做到这一点。仔细看一下,如果您有任何问题,请告诉我。具体了解为什么您不需要需要在结构中声明数组:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 500
// typedef struct __Packet {
// int Source[500];
// int Destination[500];
// int Type[500];
// int Port[500];
// char Data[60];
// } Packet;
typedef struct { /* don't use initial 'C'aps - c isn't c++ or visual basic */
int src; /* obviously, you are free to do so, but it's ugly... */
int dest;
int type;
int port;
char *data;
} packet;
int main () {
// banner (); //call on banner
// int exists (const char *filename);
// const char s[2] = ":";
// char filename[500];
// char *token;
// int n;
// struct Packet;
// Packet *P;
char *filename = NULL;
FILE *iFile = NULL;
// FILE *oFile = NULL;
char *line = NULL; /* NULL forces getline to allocate */
size_t n = 0; /* max chars to read (0 - no limit */
ssize_t nchr = 0; /* number of chars actually read */
size_t idx = 0; /* packet array index */
char *p = NULL; /* general pointer to parse line */
char *sp = NULL; /* pointer to save start address */
int i = 0; /* general iterator */
/* allocate an array of pointers to struct */
packet **pkt = calloc (MAXS, sizeof (*pkt));
if (!pkt) {
fprintf (stderr, "error: allocation failed (**pkt)\n");
exit (EXIT_FAILURE);
}
printf ("\n Input the file name: ");
scanf ("%m[^\n]%*c", &filename); /* older scanf versions use 'a' instead of 'm' */
printf ("\n");
iFile = fopen (filename, "r");
if (!iFile) {
fprintf (stderr, "error: unable to open file '%s'\n", filename);
exit (EXIT_FAILURE);
}
/* read each line in iFile */
while ((nchr = getline (&line, &n, iFile)) != -1)
{
if (nchr < 4) /* if blank or short line, skip */
continue;
if (line[nchr-1] == '\n') /* strip newline from end */
line[--nchr] = 0;
sp = line; /* save start address for getline */
pkt[idx] = calloc (1, sizeof (**pkt)); /* allocate structure */
if (!pkt[idx]) {
fprintf (stderr, "error: allocation failed (pkt[%zd])\n", idx);
exit (EXIT_FAILURE);
}
/* parse line and fill struct */
if ((pkt[idx]->src = atoi (strtok (line, ":"))))
{
pkt[idx]->dest = atoi (strtok (NULL, ":"));
pkt[idx]->type = atoi (strtok (NULL, ":"));
pkt[idx]->port = atoi (strtok (NULL, ":"));
if ((p = strtok (NULL, ":")))
pkt[idx]->data = strdup (p);
}
idx++; /* increment pkt array index */
line = sp; /* restore start address of line */
}
if (line) free (line); /* free buffer allocated by getline */
if (iFile) fclose (iFile); /* close file stream when done */
if (filename) free (filename); /* free memory allocate by scanf */
/* print array (you can also use 'for (i=0; i<idx; i++)' to iterate)*/
printf (" array of struct content:\n\n");
while (pkt[i])
{
printf (" pkt[%d] src: %4d dest: %4d type: %4d port: %4d data: %s\n",
i, pkt[i]->src, pkt[i]->dest, pkt[i]->type, pkt[i]->port, pkt[i]->data);
i++;
}
i = 0; /* reset iterator variable to zero */
while (pkt[i]) /* free all memory allocated */
{
if (pkt[i]->data) free (pkt[i]->data);
free (pkt[i]);
i++;
}
if (pkt) free (pkt);
printf ("\n"); /* make it pretty */
return 0;
}
输入:
$ cat dat/structrd.txt
0001:0002:0003:0021:CLS
0001:0010:0003:0021:CLS
0001:0002:0002:0080:
0005:0002:0002:8080:
0005:0012:0002:8080:
输出:
$ ./bin/struct_rd_txt
Input the file name: dat/structrd.txt
array of struct content:
pkt[0] src: 1 dest: 2 type: 3 port: 21 data: CLS
pkt[1] src: 1 dest: 10 type: 3 port: 21 data: CLS
pkt[2] src: 1 dest: 2 type: 2 port: 80 data: (null)
pkt[3] src: 5 dest: 2 type: 2 port: 8080 data: (null)
pkt[4] src: 5 dest: 12 type: 2 port: 8080 data: (null)
注意:在使用破坏原始缓冲区的函数(如strtok)时,需要保存getline分配的缓冲区的起始地址,以便getline可以准确保留跟踪它正在使用的内存。 (如果你不:)
使用fgets的版本
如果您没有可用的getline,请使用fgets。那是另一个合适的工具。然后放慢速度,阅读man page,看看它是如何使用的。然后您可以正确更新程序。这将包括以下更改:
// size_t n = 0; /* max chars to read (0 - no limit */
...
line = calloc (MAXS, sizeof (char));
if (!line) {
fprintf (stderr, "error: allocation of line failed.\n");
exit (EXIT_FAILURE);
}
/* read each line in iFile */
// while ((nchr = getline (&line, &n, iFile)) != -1)
while ((fgets (line, MAXS, iFile)) != NULL)
{
nchr = strlen (line);