-1

Like the title says the portion of code

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

prints all the way up to the age part of the struct array, when I really just want it to print the "first" portion

in addition to that, I can't get the actual printWorkers() function to work (note that I have not set up the actual printing correctly inside that function, it is just a place holder)

this is the portion of .txt file it is reading

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

The spaces don't appear the same in the above text as it does in the file.

The last thing I'm wondering is why a random character is being appended to the end of zip variable when it's printed out (not that I'm entirely sure it matters since it isn't supposed to print it)

It's also worth mentioning that because of my requirements the struct cannot be altered in any way.

#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 Answers2

1

You probably should take into account that printable strings are zero-byte terminated in C. Hence the fields in your anonymous struct should each have one more byte (so char first[8]; and char initial[2]; etc...). BTW the space for the last (family) name is really too small: my name won't fit in it, and is not that unusually wide.

You also should test the result of scanf & sscanf. They return the number of scanned items. You might use %5s to scan a field of 5 characters (+1 for the terminating zero byte). You should read the documentation of scanf before using it.

You should probably clear workers[i] e.g. with memset(workers+i, 0, sizeof(workers[i])); before filling it.

BTW, compile your program with all warnings & debug info (e.g. gcc -Wall -g if using GCC...) and use the debugger (e.g. gdb) e.g. to run it step by step.

Perhaps you should consider using pointers to the heap and C dynamic memory allocation. Then be sure to test against failure of malloc and beware of memory leaks; a tool like valgrind would be very helpful.


BTW, a printf call like printf("%s", workers[0].first); is having an undefined behavior (UB) when workers[0].first is a field or array of char-s which is not zero-byte terminated. And UB is really bad, you always should avoid it. Read Lattner's blog entries about undefined behavior.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Thank you for your response, the length allowed for the last name is dictated by my assignment. I'm using code:blocks and visual studio to debug, but they aren't picking any errors up. I guess I'm really just trying to find out why my printf("%s", workers[0].first); is printing out way more than I need. Is it because of the function scanning the file, or an incorrect print function? – Cole Kujawa Jun 20 '16 at 06:21
  • Also wondering where the random character comes from after the zip when compiled – Cole Kujawa Jun 20 '16 at 06:26
  • Is there a way I could zero-byte terminate each array? – Cole Kujawa Jun 20 '16 at 07:08
  • I guess I also should've mentioned this is for my first programming class, and is my final which is due in roughly 23hrs, so I do plan on learning more about debuggers, when I have more time. P.S. this is for an accelerated class 4 credits, in 4 weeks. So I have done as much studying as physically possible. – Cole Kujawa Jun 20 '16 at 07:12
  • You probably should study even more to get your exam. Good luck! – Basile Starynkevitch Jun 20 '16 at 07:30
1

Your code contains an undefined behavior. This function strsub(buf, workers[i].first, 0, 6) will write outside of array boundary:

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';
}

After the loop a j variable would be 7 and you will overwrite adjusted struct members. This is a root of your problems with the sprintf function and incorrect symbol output.

However the main problem is in your reading algorithm. You are taking parts of the fixed length from the input string. But different people have a names of different lengths. Lets consider your example

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

firstName is expected to be ADA. Yet since you are taking fixed 7 characters from the string it will be ADA A A. Is a data sting dont have a sufficient length you will be reading outside its boundary which is an undefined behavior as well.

Ari0nhh
  • 5,720
  • 3
  • 28
  • 33
  • Like I noted in the question, "The spaces don't appear the same in the above text as it does in the file." There is actually 4 spaces after the "ADA", the reason for the fixed lengths is because the assignment requires a limit on how many characters each variable can be. So that if a name came in that was longer, the excess would be cut off. Is there a way to prevent the strsub function from writing outside of the array boundary? – Cole Kujawa Jun 20 '16 at 07:04
  • Well if your file contains name that is longer than 7 symbols it would not be cutted off. Lets take name `AUGUSTINUS` for example. First 7 symbols `AUGUSTI` would be in the `firstName` member, then `N` in the `initial` and `US nextdata` will go to the `last`. You can not parse your data strings without searching for spaces, it would never work. – Ari0nhh Jun 20 '16 at 07:12
  • Well then, I guess I'm not sure why it is required, but the assignment requires it. Most everything prints out ok, just some of them print out the whole set of arrays instead of the one intended. Which means either the print is printing out more than necessary or the strsub function is reading in too much. – Cole Kujawa Jun 20 '16 at 07:16
  • These are two *different* things - requirement for the variables of fixed length and fixed size reading from the buffer. You could scan input string until you found space character to get a first name, and if it is greater than the desired amount - cut it off. That way it will always work correctly no matter how many symbols were passed. As for the UB with reading - increase all array sizes for one character. It should fix this issue. – Ari0nhh Jun 20 '16 at 07:23
  • That fixed it. Thank you so much. – Cole Kujawa Jun 20 '16 at 07:40