【问题标题】:Read space delimited file with variable number of columns in C在C中读取具有可变列数的空格分隔文件
【发布时间】:2013-10-12 17:17:06
【问题描述】:

所以我的文件格式如下:

2
4 8 4 10 6
9 6 74 

第一行实际上是文件后面的行数。我想逐行读取文件(请注意,每行中有不同数量的标记,但都具有格式:1 个标记,然后是未指定数量的标记对)并为每一行做两件事:

1) 知道这一行有多少个标记。

2) 将每个标记分配给一个变量。使用类似于以下的结构:

typedef struct {
  unsigned start; //start node of a graph 
  unsigned end;   // end node of a graph
  double weight;  //weight of the edge going from start to end
} edge ;

typedef struct {
  unsigned id;   // id of the node
  unsigned ne;   // number of edges adjacent to node
  edge *edges;   // array of edge to store adjacent edges of this node
} node;

一些代码:

FILE *fin;
unsigned nn;
node *nodes;

fin = fopen ("input.txt", "r");
fscanf(fin,"%u\n", &nn);

nodes = malloc(nn*sizeof(node));

for(i=0; i < nn; i++) { //loop through all the rows
/*grab the row and split in parts, let's say they are part[0], part[1]... */
/*and there are N tokens in the row*/
  nodes[i].id=part[0];
  nodes[i].ne=(N-1)/2; //number of pairs excluding first element
  nodes[i].edges=malloc( (N-1)/2)*sizeof(edge) );
  for(j=0; j< (N-1)/2; j++){
    nodes[i].edges[j].start=part[0];
    nodes[i].edges[j].end=part[2*j+1];
    nodes[i].edges[j].weight=part[2*j+2];
  }
}

我需要弄清楚如何执行第一个 for 循环中注释的部分,以获取令牌的数量,并将它们中的每一个作为要分配的简单令牌。有什么想法吗?

编辑:为了清楚起见,每一行都有第一个整数,然后是可变数量的对。我想按如下方式存储数据:

如果文件读取

2
4 8 4 10 6 //(2 pairs)
9 6 74 //(1 pair)   

然后

nn=2;

node[0].id=4;
node[0].ne=2; //(2 pairs)
node[0].(*edges) //should be a vector of dimension ne=2 containing elements of type edge

node[0].edges[0].start=4; //same as node[0].id
node[0].edges[0].end=8;
node[0].edges[0].weight=4;

node[0].edges[1].start=4; //same as node[0].id
node[0].edges[1].end=10;
node[0].edges[1].weight=6;

node[1].id=9;
node[1].ne=1; //(1 pair)
node[1].(*edges) //should be a vector of dimension ne=1 containing elements of type edge

node[1].edges[0].start=9; //same as node[1].id
node[1].edges[0].end=6;
node[1].edges[0].weight=74;

【问题讨论】:

  • 所以实际上你不知道如何在 C 中读取文件 因为缺少该代码。
  • 你想分割行,Gunb 需要在文件中寻找\n 来读取行。当然,在使用 strtok() 进行解析之后
  • 感谢您对结构进行评论 - 一个节点是否真的只是一对 x,y 对,就像点 (x,y) 一样?
  • 我在一个小例子中添加了一个小摘要,说明我希望如何将每一行的变量存储在结构中。我希望它有助于澄清事情。

标签: c file variables structure


【解决方案1】:

此代码产生您描述的结果,它初始化您的嵌套结构成员edge,并使用 strtok。对于strtok(),除了空格" \n" 之外,我还包含了\n 作为分隔符的一部分,以防止换行符给我们带来麻烦(请参阅下面的其他cmets)

注意:您必须在我指出的地方释放内存,但在此之前,请保留中间结果(在结构中),否则它将丢失。

#include <ansi_c.h>

typedef struct {
  unsigned start;
  unsigned end;
  double weight;
} edge ;

typedef struct {
  unsigned id;
  unsigned ne;
  edge *edges;
} node;

int GetNumPairs(char *buf);

int main(void)
{
    FILE *fp;
    char *tok;
    char lineBuf[260];
    int i=0, j=0;
    int nn; //number of nodes
    char countPairsBuf[260];

    fp = fopen("C:\\dev\\play\\numbers.txt", "r");
    //get first line of file for nn:
    fgets (lineBuf, sizeof(lineBuf), fp);
    nn = atoi(lineBuf);
    //create array of node with [nn] elements
    node n[nn], *pN;
    pN = &n[0];

    //read rest of lines, (2 through end)
    i = -1;
    while(fgets (lineBuf, sizeof(lineBuf), fp))
    {
        i++;
        //get number of items in a line
        strcpy(countPairsBuf, lineBuf);
        pN[i].ne = GetNumPairs(countPairsBuf); //number of edges (pairs)
        if(pN[i].ne > 0)
        {   //allocate *edges struct element
            pN[i].edges = malloc((pN[i].ne)*sizeof(edge));
            //get first item in new line as "line token" and "start"
            tok = strtok(lineBuf, " \n");
            while(tok)
            {
                pN[i].id = atoi(tok);
                //now get rest of pairs
                for(j=0;j<pN[i].ne;j++)
                {
                    pN[i].edges[j].start = pN[i].id;
                    tok = strtok(NULL, " \n");
                    pN[i].edges[j].end = atoi(tok);
                    tok = strtok(NULL, " \n");
                    pN[i].edges[j].weight = atoi(tok);
                }
                tok = strtok(NULL, " \n"); //should be NULL if file formatted right
            }
        }
        else  //pN[i].ne = -1
        {
            //error, file line did not contain odd number of elements   
        }

    }
    //you have to free memory here
    //but I will leave that to you
    fclose(fp);

}


//GetNumPairs
int GetNumPairs(char *buf)
{
    int len = strlen(buf);
    int numWords=0, i, cnt=0;

    for(i=0;i<len;i++)
    {
        if ( isalpha ( buf[i] ) ) cnt++;
        else if ( ( ispunct ( buf[i] ) ) || ( isspace ( buf[i] ) ) )
        {
            numWords++;
            cnt = 0;
        }
    }//if odd number of "words", return number of pairs, else error
    return (((numWords-1)%2) == 0) ? ((numWords-1)/2) : (-1);
}   

【讨论】:

  • 好的,我编辑这个。结构成员“start”和“end”有什么用?
  • startend 表示图中边的开始和结束节点。我对++i 语法不是很熟悉。它确实使用了i 的旧值,然后增加它的值?
  • @ryyker \n 在 strtok 中不是必需的;它甚至让我感到困惑:)
  • ++i 与 i++ 相反,在 before 使用它之前递增 i。另一个问题:哪个结构成员用于存储每行中的标记对数?即,您是否需要了解如何在结构中存储令牌对数组?
  • @RobinRobinovic:\n 是个好主意;它可以防止换行被视为行上最后一个标记的一部分。请记住,fgets() 在输出中包含换行符。
猜你喜欢
  • 2013-08-04
  • 2013-11-07
  • 1970-01-01
  • 2017-08-20
  • 1970-01-01
  • 2012-05-05
  • 2013-06-03
相关资源
最近更新 更多