C程序结构使用文件输入和输出

时间:2016-05-22 07:26:55

标签: c file loops io structure

第一个C编程课并开始学习编程。我目前正在学习如何在C中使用文件输入/输出,这是一个学习任务,以帮助理解这个过程。

该任务要求程序使用具有随机美国地址的输入文件,然后按照从最小到最大的顺序输出地址。由于程序现在站立不会崩溃,但我得到一个空的输出文件。我可能知道出了什么问题。我相信我必须告诉程序/函数何时开始读取输入文件,然后何时写入,最后何时关闭文件。可能在某处使用'while'语句?

需要什么以及在何处让此程序将地址输出到文件中?有人可以推荐一个可以添加的功能/声明来实现这个目标吗?

非常感谢您提供帮助,时间和指导,让您的计划有效!

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
@WebIntegrationTest
public class DemoControllerTest  {

    @Test
    public void test() {
        get("/lotto").then().assertThat().body("lotto.lottoId", equalTo(5));
    }

}

使用的输入:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFF_SIZE 32
#define STRUCT_SIZE 512

struct info {
    char name[BUFF_SIZE];
    char stAddress[BUFF_SIZE];
    char cityAndState[BUFF_SIZE];
    char zip[BUFF_SIZE];
};

void selectionSort(struct info *ptrStruct[], int size);

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

    FILE *fpin, *fpout;
    int count, size;
    char buffer[512];
    struct info *ptrStruct[STRUCT_SIZE];

    if (argc != 3) {

        printf("Usage: program, inputfile, outputfile\n");
        exit(1);
    }

    if ((fpin = fopen(argv[1], "r")) == NULL) {

        printf("Can't open input file\n");
        exit(1);

    }

    if ((fpout = fopen(argv[2], "w")) == NULL) {

        printf("Can't open output file\n");
        exit(1);
    }

    for (count = 0; count < STRUCT_SIZE; count++){
        ptrStruct[count] = (struct info*) malloc(sizeof(struct info));
        if (EOF == scanf("%599[^\n]%*c", buffer)){
            free(ptrStruct[count]);
            break;
        };
        strcpy(ptrStruct[count]->name, buffer);
        scanf("%511[^\n]%*c", buffer);
        strcpy(ptrStruct[count]->stAddress, buffer);
        scanf("%511[^\n]%*c", buffer);
        strcpy(ptrStruct[count]->cityAndState, buffer);
        scanf("%511[^\n]%*c", buffer);
        strcpy(ptrStruct[count]->zip, buffer);
    }

    size = count;
    selectionSort(ptrStruct, size);

    printf("\n\nLEAST TO GREATEST\n");
    for (count = 0; count < size; count++)
    {
        printf("%s\n", ptrStruct[count]->name);
        printf("%s\n", ptrStruct[count]->stAddress);
        printf("%s\n", ptrStruct[count]->cityAndState);
        printf("%s\n", ptrStruct[count]->zip);
        free(ptrStruct[count]);
    }

fclose(fpin);
fclose(fpout);

}

void selectionSort(struct info *ptrStruct[], int size)
{
    int count1, count2;
    int minIndex;
    struct info *ptrTemporary;

    for (count2 = 0; count2 < size - 1; count2++)
    {
        minIndex = count2;
        for (count1 = count2 + 1; count1 < size; count1++)
        {
            if (strcmp(ptrStruct[count1]->zip, ptrStruct[minIndex]->zip) < 0)
                minIndex = count1;
        }
        if (minIndex != count2){
            ptrTemporary = ptrStruct[count2];
            ptrStruct[count2] = ptrStruct[minIndex];
            ptrStruct[minIndex] = ptrTemporary;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

第一个mainint类型的函数,应该return为shell的值。虽然并非在所有情况下都是强制性的,但最好初始化所有变量(特别是在您不熟悉C时)。

虽然不是错误,但C的标准编码样式避免使用caMelCase变量来支持所有小写。参见例如NASA - C Style Guide, 1994

您的阅读循环显示您对如何将输入文件中的数据导入程序感到困惑。您的BUFF_SIZE常量为32,但显然已在buffer返回并硬编码512,猜测这可能有助于您输入您的程序。 (您无法猜测通往C语言的有效解决方案......)

您最长的输入行是22个字符,因此+1的{​​{1}}和'\n' nul-terminated 字符的+1表示您最长的行需要'\0'个字符才能存储。这超出了24

您的输入例程要求您一次读取一行。使用面向行的输入函数(如BUFF_SIZE 32fgets)可以更好地完成此操作。此外,您需要确保构成地址的所有4行一起读取并且所有成功读取或不存储任何数据。 (您不希望存储部分地址)。如果你只是检查每一个并且在任何一个上失败(并继续循环),那么getlinenameaddresscitystate将会在下一个不同步读。

以一种有意义的方式完成此任务的方法是使用zip结构的静态实例来构建每个地址。​​然后,一旦所有成员都包含经过验证的值,请将该信息添加到你的指针数组。

例如,您的读取循环可以完成如下操作:

info

注意: for (idx = 0; idx < MAXS;) { int a1, a2, a3, a4; char buf[MAXB] = ""; struct info tmp = { .name = "" }; if (!fgets (buf, MAXB, fp)) break; /* read/validate lines */ a1 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') || !sscanf (buf, "%31[^\n]", tmp.name)); if (!fgets (buf, MAXB, fp)) break; a2 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') || !sscanf (buf, "%31[^\n]", tmp.address)); if (!fgets (buf, MAXB, fp)) break; a3 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') || !sscanf (buf, "%31[^\n]", tmp.citystate)); if (!fgets (buf, MAXB, fp)) break; a4 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') || !sscanf (buf, "%31[^\n]", tmp.zip)); if (a1 || a2 || a3 || a4) continue; /* any error, skip all lines */ if (!(addr[idx] = malloc (sizeof *addr[idx]))) { fprintf (stderr, "error: virtual memory exhausted.\n"); return 1; } /* copy tmp to addr[idx] and increment index */ memcpy (addr[idx++], &tmp, sizeof tmp); } 只检查(1)buf[MAXB - 2] && buf[MAXB - 2] != '\n'是否已满,以及(2) nul-terminated 字符不是buf表示简短阅读,并且该行中的字符数超过'\n'(您的MAXB - 我不&# 39; t喜欢打字))

至于你的BUFF_SIZE指针,你只需要一个FILE *指针。 (您一次不会打开多个流)。至于输出函数,如果你考虑它,你只需要一个输出函数来处理终端(例如fp文件流)或任何文件(例如stdout)的输出。因此,您可以根据需要简单地创建单个打印功能。例如:

fp = fopen (somefile, "w")

这只是提供了一种理智的单行输出格式,例如:

/** write 'n' addresses to FILE *fp */
void prnaddr (struct info **addr, int n, FILE *fp)
{
    int i;
    for (i = 0; i < n; i++)
        fprintf (fp, " %-8s    %-22s    %-20s    %s\n", addr[i]->name,
                addr[i]->address, addr[i]->citystate, addr[i]->zip);
}

将所有部分放在一起,并注意到当您需要声明多个常量时,您可以简单地使用单个全局 K1, K2 720 Eucalyptus Ave 105 Inglewood, CA 89030 O1, O2 7659 Mckinley Ave Los Angeles, CA 90001 G1, G2 20253 Lorenzana Dr Los Angeles, CA 90005 而不是多个enum行(并将常量的名称缩短为{ {1}}(最大字符数)和#define(最大结构数),您可以执行类似以下操作:

MAXC

<强>输入

您提供的输入文件已被使用。

示例使用/输出

MAXS

文件输出

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum { MAXB = 32, MAXS = 512 };

struct info {
    char name[MAXB];
    char address[MAXB];
    char citystate[MAXB];
    char zip[MAXB];
};

void prnaddr (struct info **addr, int n, FILE *fp);
void selectionSort(struct info *addr[], int size);

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

    int i, idx = 0;
    struct info *addr[MAXS] = {NULL};
    FILE *fp = NULL;

    if (argc != 3) {
        printf("Usage: program, inputfile, outputfile\n");
        exit(1);
    }
    if ((fp = fopen(argv[1], "r")) == NULL) {
        printf("Can't open input file\n");
        exit(1);
    }

    for (idx = 0; idx < MAXS;) {
        int a1, a2, a3, a4;
        char buf[MAXB] = "";
        struct info tmp = { .name = "" };

        if (!fgets (buf, MAXB, fp)) break; /* read/validate lines */
        a1 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') || 
            !sscanf (buf, "%31[^\n]", tmp.name));

        if (!fgets (buf, MAXB, fp)) break;
        a2 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
            !sscanf (buf, "%31[^\n]", tmp.address));

        if (!fgets (buf, MAXB, fp)) break;
        a3 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
            !sscanf (buf, "%31[^\n]", tmp.citystate));

        if (!fgets (buf, MAXB, fp)) break;
        a4 = ((buf[MAXB - 2] && buf[MAXB - 2] != '\n') ||
            !sscanf (buf, "%31[^\n]", tmp.zip));

        if (a1 || a2 || a3 || a4) continue; /* any error, skip all lines */

        if (!(addr[idx] = malloc (sizeof *addr[idx]))) {
            fprintf (stderr, "error: virtual memory exhausted.\n");
            return 1;
        }
        /* copy tmp to addr[idx] and increment index */
        memcpy (addr[idx++], &tmp, sizeof tmp);
    }
    fclose(fp);

    selectionSort(addr, idx);

    printf("\nLEAST TO GREATEST\n");
    prnaddr (addr, idx, stdout);

    if ((fp = fopen(argv[2], "w")) == NULL) {
        printf("Can't open output file\n");
        exit(1);
    }
    prnaddr (addr, idx, fp);
    fclose(fp);

    for (i = 0; i < idx; i++) free(addr[i]);

    return 0;
}

/** write 'n' addresses to FILE *fp */
void prnaddr (struct info **addr, int n, FILE *fp)
{
    int i;
    for (i = 0; i < n; i++)
        fprintf (fp, " %-8s    %-22s    %-20s    %s\n", addr[i]->name,
                addr[i]->address, addr[i]->citystate, addr[i]->zip);
}

void selectionSort(struct info *addr[], int size)
{
    int idx1, idx2;
    int minIndex;
    struct info *ptrTemporary;

    for (idx2 = 0; idx2 < size - 1; idx2++)
    {
        minIndex = idx2;
        for (idx1 = idx2 + 1; idx1 < size; idx1++)
        {
            if (strcmp(addr[idx1]->zip, addr[minIndex]->zip) < 0)
                minIndex = idx1;
        }
        if (minIndex != idx2){
            ptrTemporary = addr[idx2];
            addr[idx2] = addr[minIndex];
            addr[minIndex] = ptrTemporary;
        }
    }
}

仔细看看,如果您有任何问题,请告诉我。

答案 1 :(得分:0)

首先,我可以看到您正在使用buffer扫描scanf变量中的数据。我至少可以在您的代码中找到以下错误:

  1. 您应该使用fscanf来读取文件fpin

  2. 您的问题还在于scanffscanf)格式规范。

  3. 此外,在scanf时,我可以看到您正在将599个字符扫描到buffer变量中,该变量的长度仅为512.这具有未定义的行为。

  4. 一种解决方案:您应该一次一行地逐行读取内容。