【问题标题】:Modify and print typedef'd array in C在 C 中修改并打印 typedef'd 数组
【发布时间】:2014-12-12 00:19:36
【问题描述】:

我正在学习使用结构,当我用 C 做一个练习时,我就产生了这个疑问。 我有这个代码:

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>

#define MAX_STRING 256
#define MAX_CHILD 2000
#define MAX_GIFTS 20
#define MAX_LINE 1024

typedef char String[MAX_STRING];
typedef char Line[MAX_LINE];

typedef struct {    
    String child_name;  
    int grade;               //integer between 0 and 5
    String gift_name;   
    int price;              //price of the gift
} Data;

typedef struct { 
    String name;        
    int price;          
    bool received;      //true if the child will get this gift

} Gift;

typedef Gift Gifts[MAX_CHILD];

typedef struct{ 
    String name;            
    int grade;      
    Gifts asked;         //gifts the child asked for
    int n_asked;        
} Child;

typedef Child Children[MAX_CHILD];

Data make_data (String line){
    Data d;
    sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
    return d;
}

Child make_child(Data d) {
    Child c;
    strcpy(c.name, d.child_name);
    c.grade = d.grade;
    c.n_asked = 0;
    return c;
}

Gift make_gift(Data d){
    Gift g;
    strcpy(g.name, d.gift_name);
    g.price = d.price;
    g.received = false;
    return g;
}

int process(char file_name[]){
    Line line;
    FILE *f = fopen(file_name, "r");
    while(fgets(line, MAX_LINE, f) != NULL){
        make_data(line);  
    }
    int fclose (FILE *f);
}

int main(){
    process("data.txt");
    return 0;
}

所以这个程序接收到这种格式的文件文本:

John 4 Bike 200
Alice 3 Computer 800
Alice 3 Candy 10
Mike 5 Skate 100

并在函数process中构造数据。

问题是,我想将所有孩子存储在数组 Children[] 中并打印它(打印所有数组或类似于 Children[0]、Children[1] 等的东西)。我尝试了一些方法,但没有成功......因为数组是儿童类型而不是 char*。即使我只是做Children cs;,我也会遇到分段错误。有没有办法我可以做到这一点?

我的第二个问题是,最初我有#define MAX_CHILD 20000,当我尝试编译时,我收到一个错误,提示“数组‘Children’的大小太大”。为什么会这样?我看到它不会发生在 Gifts 上,但会发生在 Children 身上,因为结构 Child 具有与成员一样的 Gifts 类型,这意味着它需要更多空间。

任何帮助表示赞赏。

【问题讨论】:

  • 关于“太大”错误,请参阅:stackoverflow.com/questions/18371584/…
  • OP 可以通过在文件空间而不是堆栈中声明数据来消除“太大”的问题。
  • 函数:process() 将导致编译器针对具有非空返回缺少实际返回语句的函数发出警告。 (为什么发布您知道无法编译的代码?)您正在启用所有警告?警告不容忽视。
  • 这不是帕斯卡编程。所以使用函数原型并使用 main() 函数“打开球”。在处理包含数千个文件和数百万行代码的应用程序时,良好的编程实践和良好习惯将为您提供支持
  • @user3629249 这段代码可以编译。所有的结构都给了我(正如我提到的,这是一个练习),我只需要构建 process() 函数,唯一缺少的就是构建 Children 数组,正如我所说的。

标签: c structure typedef


【解决方案1】:
the use of the typedef's (and so on) 
instead of just writing the code out where it is needed
is unneeded (and distracting) and mis-leading and 
makes the code much more difficult to follow.

This function:

Data make_data (String line)
{
    Data d;
    sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
    return d;
}

has several problems:
1) the parameter list will cause the compiler to 'set aside' enough room
   for the String struct,
   invoke a memcpy() to copy the String struct
   to that 'set aside' memory from the callers' memory
   Then copy the 'set aside' memory to the called functions' stack
   That 'set aside' memory will never be used for anything else
   The stack will be cluttered with the contents of the String struct
   until the function returns
   such activity is a real 'bear' to debug
2) the returned value from sscanf() needs to be checked
   to assure that all 4 conversion operations were successful
3) the function return is a instance of the Data struct.
   This will cause the compiler to 'set aside' enough room
   for the Data struct.
   that 'set aside' memory will never be used for anything else
   invoke a memcpy() to copy the Data struct from the stack
   to the 'set aside' memory
   then perform the return from the function
   then the compiler will cause the caller to 
   invoke memcpy() to copy the Data struct
   from the 'set aside' memory to the caller's Data struct area.
   such activity is a real 'bear' to debug.

The function should be written more like this:

int make_data (String *pLine, Data* pData)
{
    int returnValue = 1; // initialize to indicate function successful

    if( 4 != sscanf(pLine," %s %d %s %d", 
                    pData->child_name, 
                   &pData->grade, 
                    pData->gift_name, 
                   &pData->price) )
    { // then sscanf failed
        perror( "sscanf failed for Line" );
        returnValue = 0; // indicate to caller that function failed
    } //  end if

    return( returnValue );
} // end function: make_data

and the caller(s) of this function should be adjusted accordingly

the make_gift() function has the same passed parameter
and returned parameter problems.

【讨论】:

  • 感谢您的帮助,但函数 Data make_data 和除 process() 之外的所有其他函数一样,都交给了我。我不想更正,我只需要构建Children数组。
【解决方案2】:

问题是,我想将所有的孩子存储在数组中 Children[ ] 并打印它(打印所有数组或只是一些东西 类似于 Children[0]、Children[1] 等)。

存储:

    static Children cs;
    size_t nc = 0;  // number of children
    while (fgets(line, MAX_LINE, f))
    {
        #include <search.h>
        Data d = make_data(line);  
        Child c = make_child(d);
        Child *cp = lsearch(&c, cs, &nc, sizeof c, (int (*)())strcmp);
        cp->asked[cp->n_asked++] = make_gift(d);
    }

打印:

    int i, j;
    for (i = 0; i < nc; ++i)
    {
        printf("%s (grade %d) asked for %d:\n",
               cs[i].name, cs[i].grade, cs[i].n_asked);
        for (j = 0; j < cs[i].n_asked; ++j)
            printf("\t%s\t%d\n", cs[i].asked[j].name, cs[i].asked[j].price);
    }

(我们不能简单地打印聚合类型对象 - 我们必须打印单个元素。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    相关资源
    最近更新 更多