Printf功能打印结构阵列的更多部分而不是预期的

时间:2016-06-20 05:57:25

标签: c

就像标题所说的代码部分

printf("%s", workers[0].first);

一直打印到struct数组的age部分,当我真的只想要它打印" first"部分

除此之外,我无法使用实际的printWorkers()函数(请注意,我没有在该函数内正确设置实际打印,它只是一个占位符)

这是正在阅读的.txt文件的一部分

" ADA A AGUSTA 33 BABBAGE ROAD LOVELACE GB 19569 28 F 2 350.50"

上述文本中的空格与文件中显示的内容不同。

我想知道的最后一件事是为什么当一个随机字符被打印出来时会附加到zip变量的末尾(不是因为它不是'我完全确定它很重要,因为它不是&# 39;应该打印它)

值得一提的是,由于我的要求,结构不能以任何方式改变。

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>

#define MAX 100

FILE *fp;
FILE *fpIn;
FILE *fpOut;

typedef struct {
    char first[7];
    char initial[1];
    char last[9];
    char street[16];
    char city[11];
    char state[2];
    char zip[5];
    int age;
    char sex[1];
    int tenure;
    double salary;
    } payroll;

int readFile();
void strsub (char buf[], char sub[], int start, int end);
void printWorkers(int numOfWorkers);
payroll workers[MAX];

int main()
{
    int numOfWorkers = 0;


        if (!(fpIn = fopen("payfile.txt", "r")))
    {
        printf("payfile.txt could not be opened for input.");
        exit(1);
    }
    if (!(fpOut = fopen("csis.txt", "w")))
    {
        printf("csis.txt could not be opened for output.");
        exit(1);
    }

    readFile();
    numOfWorkers = readFile();
    printWorkers(numOfWorkers);

    printf("%s", workers[0].first);
    printf(" %d", workers[0].age);
    printf(" %s", workers[0].sex);
    printf(" %d", workers[0].tenure);
    printf(" %.2lf", workers[0].salary);


    return 0;
}


int readFile()
{
    int i = 0;
    char buf[MAX];
    while(!feof(fpIn))
    {

            fgets(buf, MAX, fpIn);
            strsub(buf, workers[i].first, 0, 6);
            strsub(buf, workers[i].initial, 8, 8);
            strsub(buf, workers[i].last, 9, 18);
            strsub(buf, workers[i].street, 19, 34);
            strsub(buf, workers[i].city, 36, 46);
            strsub(buf, workers[i].state, 48, 49);
            strsub(buf, workers[i].zip, 51, 56);
            sscanf(buf+58, "%2d", &workers[i].age);
            strsub(buf, workers[i].sex, 61, 61);
            sscanf(buf+63, "%d", &workers[i].tenure);
            sscanf(buf+65, "%lf", &workers[i].salary);

            ++i;

    }

    return i;
}

void strsub (char buf[], char sub[], int start, int end)
{
    int i, j;

    for (j=0, i=start; i <= end; i++, j++)
    {
        sub[j] = buf[i];
    }
    sub[j] = '\0';
}

void printWorkers(int numOfWorkers)
{
    int i;

    for (i = 0; i < numOfWorkers; i++)
    {
        printf("%7s %2s %10s %17s %12s %3s %6s %3d %2s %5d %.2lf\n",
                    workers[i].first, workers[i].initial, workers[i].last, workers[i].street, workers[i].city,
                    workers[i].state, workers[i].zip, workers[i].age, workers[i].sex, workers[i].tenure, workers[i].salary);
    }
}

2 个答案:

答案 0 :(得分:1)

您可能应该考虑到可打印的字符串在C 中以零字节终止。因此,匿名struct中的字段应该每个字节都有一个字节(所以char first[8];char initial[2];等等)。 BTW last(家庭)名称的空间实在太小了:我的名字不适合它,而且不是那么宽。

您还应该测试scanf & sscanf的结果。它们返回扫描项目的数量。您可以使用%5s扫描5个字符的字段(终止零字节为+1)。在使用之前,您应该阅读scanf的文档。

您应该清除workers[i],例如在填写之前使用memset(workers+i, 0, sizeof(workers[i]));

顺便说一下,用所有警告编译你的程序&amp;调试信息(例如gcc -Wall -g如果使用GCC ...)和使用调试器(例如gdb),例如一步一步地运行它。

也许您应该考虑使用指向堆的指针C dynamic memory allocation。然后一定要测试malloc的失败,并注意memory leaks;像valgrind这样的工具会非常有用。

BTW,当printfprintf("%s", workers[0].first);的字段或数组时,workers[0].first char这样的B b = new B(); 调用有undefined behavior(UB) 零字节终止。 UB真的是bad,你总是应该避免它。阅读Lattner's blog entries about undefined behavior

答案 1 :(得分:1)

您的代码包含未定义的行为。此函数strsub(buf, workers[i].first, 0, 6)将在数组边界外写入:

void strsub (char buf[], char sub[], int start, int end)
{
    int i, j;

    for (j=0, i=start; i <= end; i++, j++)
    {
        sub[j] = buf[i];
    }
    sub[j] = '\0';
}

循环后,j变量为7,您将覆盖已调整的struct成员。这是sprintf函数和错误符号输出问题的根源。

然而,主要问题在于您的阅读算法。您正在从输入字符串中获取固定长度的一部分。但是不同的人有不同长度的名字。让我们考虑你的例子

  

&#34; ADA A AGUSTA 33 BABBAGE ROAD LOVELACE GB 19569 28 F 2 350.50&#34;

firstName预计为ADA。然而,由于你从字符串中取出固定的7个字符,它将是ADA A A。数据sting是否没有足够的长度,你将在其边界外读取,这也是一个未定义的行为。