我对使用C编程很新,我想要做的是将文件中的数据输入到数据结构中。我意识到我有一些错误,我无法弄明白。任何帮助将不胜感激。
我正在阅读的文本文件包含:
0001:0002:0003:0021:CLS
0001:0010:0003:0021:CLS
0001:0002:0002:0080:<HTML>
0005:0002:0002:8080:<BR>
0005:0012:0002:8080:<BR>
我的代码是:
int main() {
banner(); //call on banner
int exists(const char *filename);
const char s[2] = ":";
char filename[500];
FILE * inputFile;
FILE * outputFile;
char *token;
int n;
struct Packet;
Packet *P;
printf("Input the file name: ");
scanf("%s",filename);
printf("\n");
inputFile = fopen(filename, "r");
if (inputFile != NULL)
{
printf("This file exists");
}
else
{
printf("This file doesn't exist\n");
while(P >=sizeof(Packet)){
P=(struct Packet*)calloc( 5, sizeof(Packet *) );
fscanf(inputFile,"%s %d %d %d", &P->S, &P->D, &P->T, &P->P, &P->D );
fprintf(inputFile,"%s %d %d %d %d\n", P->S, P->D, P->T, P->P, P->D);
}
while(!feof(inputFile)){
{
P=(Packet*)calloc( 5, sizeof(struct Packet *) );
fscanf(inputFile,"%s %d %d %d", P->S, P->D, P->T, P->P, P->D );
fprintf(inputFile,"%d %d %d %d %s\n", P->S, P->D, P->T, P->P, P->D);
}
}
答案 0 :(得分:1)
您面临的最大挑战是为工作选择正确的工具。您还必须将结构声明与您拥有的数据相匹配。
虽然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)
注意:当您使用破坏原始缓冲区的函数(如getline
)时,需要保存strtok
分配的缓冲区的起始地址,以便{{ 1}}可以准确地跟踪它正在使用的内存。 (如果你没有getline
版本使用:)
如果对于某些奇怪的阅读,您没有fgets
可用,请使用getline
。这是另一个合适的工具。然后放慢速度并阅读fgets
以查看它是如何使用的。然后,您可以正确更新程序。这将包括以下更改:
man page
答案 1 :(得分:0)
我发现的一些错误是:
while(P >=sizeof(Packet))
这项检查似乎毫无意义。请查看EOF
常量以确定何时结束循环。(struct Packet*)
此处不要使用关键字struct
,因为Packet
已经是结构的typedef。calloc(5, sizeof(Packet *))
您不想分配指针的大小,而是分配实际结构的大小。&P->Source, &P->Destination, ...
您不必传递数组地址(&
),因为数组本身是指针。fprintf(inputFile,"%s %d %d %d %d\n"
%s
说明符应该是最后一个,因为第一个说明符是int数组。此外,您必须取消引用int
数组才能打印数字。我认为你应该更详细地研究数组和指针。