【问题标题】:NULL-terminated array of struct types in CC中以NULL结尾的结构类型数组
【发布时间】:2014-05-09 06:51:39
【问题描述】:

我正在尝试构建一个以 NULL 结尾的结构数组

这里是代码:lzdata.c

#include <stdlib.h>
#include <stdio.h>
#include "nist.h"

int main(int argc,char *argv[])
{

    nist_t *nist; /* NIST data */

    nist=readnist();
}

文件nist.c

#include <stdlib.h>
#include <stdio.h>
#include "nist.h"

nist_t *readnist()
{
    nist_t *nist; /* NIST data */
    char line[50];
    int len=50;
    int i=0;

    nist=(nist_t*)malloc(sizeof(nist_t));
    while(fgets(line,len,stdin))
    {
        nist=(nist_t*)realloc(nist,sizeof(nist_t)*(i+1));
        sscanf(line,"%s %s %f %lf",nist[i].config,nist[i].term,&(nist[i].j),&(nist[i].level));
        ++i;
    }
    nist=(nist_t*)realloc(nist,sizeof(nist_t)*(i+1));
    nist[i]=(nist_t)NULL;

    return nist;
}

头文件nist.h:

#ifndef NIST_H
#define NIST_H

typedef struct
{
    char config[3];
    char term[4];
    float j;
    double level;
} nist_t;

nist_t *readnist();


#endif

数据文件,将通过 STDIN 提供给应用程序:

2s  ¹S   0.0    0.000000
2p  ³P°  1.0    142075.333333
2p  ¹P°  0.0    271687.000000
2p  ³P   1.0    367448.333333
2p  ¹D   0.0    405100.000000
2p  ¹S   0.0    499633.000000
3s  ³S   0.0    1532450.000000
3s  ¹S   0.0    1558080.000000
3p  ¹P°  0.0    1593600.000000
3p  ³P°  1.0    1597500.000000
3d  ³D   1.0    1631176.666667
3d  ¹D   0.0    1654580.000000
3s  ³P°  1.0    1711763.333333
3s  ¹P°  0.0    1743040.000000
3p  ³D   1.0    1756970.000000
3p  ³S   0.0    1770380.000000
3p  ³P   0.5    1779340.000000
3p  ¹D   0.0    1795870.000000
3d  ³P°  1.0    1816053.333333
3d  ¹F°  0.0    1834690.000000
3d  ¹P°  0.0    1841560.000000
...
...

当我编译时:

$ cc -O2 -o lzdata lzdata.c nist.c nist.c: In function ‘readnist’: nist.c:24:2: error: conversion to non-scalar type requested

我尝试将行 nist[i]=(nist_t)NULL; 更改为 nist[i]=(nist_t*)NULL; 并得到:

$ cc -O2 -o lzdata lzdata.c nist.c nist.c: In function ‘readnist’: nist.c:24:9: error: incompatible types when assigning to type ‘nist_t’ from type ‘struct nist_t *’

我尝试将行 nist[i]=(nist_t)NULL; 更改为 nist[i]=NULL; 并得到:

$ cc -O2 -o lzdata lzdata.c nist.c nist.c: In function ‘readnist’: nist.c:24:9: error: incompatible types when assigning to type ‘nist_t’ from type ‘void *’

不同数据文件中的行数可能不同。我正在寻求构建一个以 NULL 结尾的 nist_t 数据数组,所以我可以处理它,直到我到达 NULL 元素。这可能吗?

【问题讨论】:

  • NULL 本身是整数值 0(尽管一些实现将其定义为指针值 0)。由于您不能将整数和结构混合在一起,因此您尝试做的事情不能按原样工作。最好通过引用返回数组的长度。
  • fgets 循环之前,您不需要初始nist_t 分配。只要确保nistNULL。并且不要分配给你传递给realloc的同一个变量,想想重新分配会发生什么会失败,然后你就会失去原来的指针。
  • 您的数组包含对象,而不是指向对象的指针,因此您不能将其设置为 null。改为使用指针数组(但您也需要为每个对象分配内存)。或者更好:只需要一个开放数组并存储计数。
  • 另外,我希望你的 configterm 字符串不会超过 2 个和 3 个字符(分别),否则你会写出界限。
  • 未终止的数组和计数变量是大多数语言执行此操作的方式,包括 C++ 的向量对象(它还存储第二个计数以跟踪在需要重新分配之前它可以得到多大)

标签: c arrays pointers struct


【解决方案1】:

对于您的编译器,宏 NULL 似乎被定义为 ((void *) 0),这是一个指向零的通用指针。因为nist[i](对于i 的任何有效值)不是不是指针,你会得到错误。

解决这个问题的最佳方法可能是通过引用将来自main 的指针传递给函数并使用它,然后返回大小。或者通过引用传递一个整数,并将其设置为大小。

还有另一种解决方案,那就是拥有一个指针数组。然后你需要分别分配每个nist_t 结构,并释放它们。然后可以使用NULL 来表示数组的结束。这实际上是argv 的工作原理,它由NULL 指针终止(因此argv[argc] 始终等于NULL)。

【讨论】:

  • NULL 被定义为实现定义的空指针常量。 0 是一种常见的定义; ((void*)0) 是另一个。
  • 没有证据表明NULL 被定义为((void*)0) 而不是0。但这没关系;重要的是 NULL 扩展为一个(实现定义的)空指针常量,它应该只被分配或与指针对象/值进行比较。
  • @KeithThompson 从最后一条错误消息中可以清楚地看出,涉及void *,这导致了有根据的猜测(注意我的回答中的措辞似乎)它被定义为@ 987654340@.
  • 啊,你说得对,我没注意到。尽管如此,NULL 是如何定义的并不重要——也许它更容易理解为什么会产生特定的错误消息。
【解决方案2】:

你有一个结构数组。 NULL 是一个空 指针 常量。结构类型没有空值——除非你自己定义了一些可区分的值。

例如,您可以修改 nist_t 类型,使其具有指示整个值是否有效的成员:

#include <stdbool.h>
typedef struct
{
    bool is_valid;
    char config[3];
    char term[4];
    float j;
    double level;
} nist_t;

然后用nist_t 元素标记数组的结尾,并将is_valid 设置为false。或者,也许您可​​以为其他成员之一使用一些无效值。

这意味着您需要小心编写处理这些结构的任何代码,以确保正确初始化 is_valid,并且不要尝试将其他成员值与 is_valid 一起使用false.

或者,如果有nist_t* 指针,您可以构建一个数组,将终止元素设置为空指针类型,并将NULL 分配给它。

但仅跟踪nist_t 对象数组中有效元素的数量可能会更简单。

NULL 的具体定义方式在这里并不重要。真正重要的是它是一个空指针常量。将NULL 分配给指针对象使其成为空指针;将它分配给任何非指针都是无效的(尽管有些情况下,不幸的是,编译器可能会让你侥幸逃脱)。

【讨论】:

  • 我刚刚为数组分配了一个附加元素,并将configterm设置为NULL。它似乎工作。谢谢。
  • @Mannix:嗯? configterm 是数组。您不能将它们设置为NULL。你到底做了什么?
  • 哦,忘了说我在typedef声明中把字符数组改成了字符指针。
【解决方案3】:

这行得通:

nist_t *readnist()
{
    nist_t *nist=NULL;  /* NIST data */
    char line[50];      /* A single line of NIST data */
    char config[10];    /* nl quantum numbers */
    char term[10];      /* Rotational term */
    float j;
    double level;       /* energy level */
    int len=50;         /* default length of string */
    int i=0;            /* counter/index variable */
    int n;              /* principal quantum number */
    char l;             /* azimuthal quantum number */
    int en=0;           /* error number */

    while(fgets(line,len,stdin))
    {
        (void)sscanf(line,"%s\t%s\t%f\t%lf",config,term,&j,&level);
        if(NULL==(nist=(nist_t*)realloc(nist,sizeof(nist_t)*(i+1))))
        {
            en=errno;
            fprintf(stderr,"Error %d: memory allocation failure\n",en);
            fprintf(stderr,"File:\t\t%s\n",__FILE__);
            fprintf(stderr,"Function:\t%s\n",__FUNCTION__);
            fprintf(stderr,"Line:\t\t%d\n",__LINE__-6);
            exit(en);
        };
        nist[i].config=(char*)malloc(sizeof(char)*(strlen(config)+1));
        nist[i].term=(char*)malloc(sizeof(char)*(strlen(term)+1));
        strcpy(nist[i].config,config);
        sscanf(config,"%d%c",&n,&l);
        nist[i].n=n;
        strcpy(nist[i].term,term);
        nist[i].j=j;
        nist[i].level=level;
        ++i;
    }
    nist=(nist_t*)realloc(nist,sizeof(nist_t)*(i+1));
    nist[i].config=NULL;
    nist[i].term=NULL;
    nist[i].j=0.0;
    nist[i].level=0.0;

    return nist;
}

这是我用来测试它的例程:

nist_t *prtnist(nist_t *nist)
{
    int i=0;

    while((NULL!=nist[i].config) && (NULL!=nist[i].term))
    {
       fprintf(stderr,"%s\t%d\t%s\t%4.1f\t%14.8e\n",nist[i].config,nist[i].n,nist[i].term,nist[i].j,nist[i].level);
        ++i;
    }
    return nist;
}

现在我必须想办法从config 字符串中取出方位角量子数。

【讨论】:

    猜你喜欢
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2010-11-23
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    相关资源
    最近更新 更多