-1
for (struct part *p = first; p != NULL; p = p->next;) {
    fwrite(&(p->num), sizeof(int), 1, inventory);
    fwrite(&(p->qoh), sizeof(int), 1, inventory);
    fwrite(p->name, sizeof(char), strlen(p->name) + 1, inventory);
}

p is a pointer to a struct instance that looks like this:

struct part{
    int num;
    int qoh;
    char *name;
    struct part *next;
};

If i store the number 8, 104, 3176, etc. in num, things are fine. However, if I store 128, 32768, or any number that uses the most significant bit of a byte (any number with a byte 1XXX-XXX), fwrite writes all 1's into all of the more significant bytes in the file, turning 128 to -128, 199 to -57, etc.

This changing of the bytes doesn't happen during program execution - only on saving to file. Looking at num = 199 and qoh = 3, after written to file, the bytes are as such:

ff ff ff c7 00 00 00 03

which should be

00 00 00 c7 00 00 00 03

I load the file into the inventory program and it loads as expected looking at the bytes. num = -57, not 199.

Am I using fwrite wrong?

Here's the storing part, as requested.

void part_new(void) {
    struct part *new;
    int num, qoh;
    char *name;

    printf("\nEnter a part number: ");
    scanf("%d", &num);
    while(getchar() != '\n');

    for (struct part *p = first; p != NULL; p = p->next) {
        if (p->num == num) {
            printf("Duplicate part number, name: %s. Canceling action.\n", p->name);
            return;
        }
    }
    printf("Enter a name: ");
    if ((name = input(PART_NAME_MAX_CHARS)) == NULL) {
        printf("Bad input.\n");
        return;
    }
    printf("Enter a QOH: ");
    scanf("%d", &qoh);
    while(getchar() != '\n');

    new = malloc(sizeof(struct part));
    new->num = num;
    new->qoh = qoh;
    new->name = malloc(strlen(name) + 1);
    strncpy(new->name, name, strlen(name) + 1);
    free(name);
    part_into_list(new);

    return;
}

and the save function:

    bool save_file(char *fname) {
    FILE *inventory;
    struct part *del;

    if ((inventory = fopen(fname, "wb")) == NULL) {
        printf("\nCould not save %s.\n", fname);
        return false;
    }

    fseek(inventory, 0 , SEEK_SET);
    for (struct part *p = first; p != NULL; p = p->next) {
        fwrite(&(p->num), sizeof(int), 1, inventory);
        fwrite(&(p->qoh), sizeof(int), 1, inventory);
        fwrite(p->name, sizeof(char), strlen(p->name) + 1, inventory);
    }

    printf("%s saved.\n", fname);
    fclose(inventory);
    return true;
}
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • 1
    Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a [mcve]. – Stargateur Jan 09 '18 at 19:45
  • 128 "as a" signed 8-bit byte *is* -1.. a matter of perspective? – user2864740 Jan 09 '18 at 19:49
  • It's pretty clear. I want the numbers to be stored correctly. The problem is they're being stored with 1's peculiarly in significant bits. I can ask the same question again with different words if you like. – Trace Myers Jan 09 '18 at 19:49
  • You know the difference between `int`s and `unsigned int`s, right? No? Look it up. – enhzflep Jan 09 '18 at 19:50
  • You're right, I don't know why it's -128. – Trace Myers Jan 09 '18 at 19:51
  • Yes I know the difference. – Trace Myers Jan 09 '18 at 19:51
  • @TraceMyers, you have described the nature of the misbehavior fairly clearly, but you have *not* adequately described the code and data that produce the error. Follow Stargateur's link for more information if you are unfamiliar with the concept of an MCVE. – John Bollinger Jan 09 '18 at 19:51
  • There is nothing that happens between storing the int in the struct and writing it that would change the information above. – Trace Myers Jan 09 '18 at 19:53
  • 1
    @TraceMyers: You haven't shown where you're assigning the values to the struct; you need to provide enough code for someone to reproduce your problem (and no more), to make an adequate [MCVE]. Odds are, you're assigning to `num` from a type like `char` that happens to be signed under your particular compiler and build settings; when the (signed) `char` is expanded to a (signed) `int`, sign extension occurs, and you see this result. People commonly assume `char` has a particular default signedness, or don't understand how sign extension works, and have problems like this. – ShadowRanger Jan 09 '18 at 19:53
  • @TraceMyers Right now, we just have to take your word for it that `num` is 199. But the output you show us tells us that `num` is not 199. You have posted conflicting statements. Noone that reads your question can resolve this conflict with the current information. If you want someone to try to fix your problem, the fastest way you get an answer if you post a complete piece of runnable code that re-produces the error you are seeing on your machine, or that you debug your code using a debugger and verify all your assumptions (such that you really are sure that num is 199) – nos Jan 09 '18 at 19:56
  • Maybe those are the odds, and I suppose I shouldn't assume I have the trust of anybody to not do something that silly. I edited to show that it's not so. – Trace Myers Jan 09 '18 at 19:57
  • 1
    Please reduce your original program to the smallest complete program that demonstrates the error. Your sample code is too big (it has a lot of irrelevant detail) and too small (it is not a complete program.) Good MCVEs generate good answers. See [mcve]. – Robᵩ Jan 09 '18 at 19:59
  • @nos the point of asking the question was to see if I was somehow using fwrite incorrectly. I guess my question has been answered. I edited the question. beside creating a file, the above code should work. – Trace Myers Jan 09 '18 at 19:59
  • 1
    @TraceMyers: I don't see anything obviously wrong off-hand; if you want to check if the data is correct when you reach `fwrite`, you might try inserting a `printf("%d %d \"%s\"\n", p->num, p->qoh, p->name);` before the `fwrite` calls, so you can check that the values are what you expect in the first place. – ShadowRanger Jan 09 '18 at 20:04
  • @ShadowRanger I have done that. That's mainly why I'm confused. – Trace Myers Jan 09 '18 at 20:18
  • The problem is **in the code that you didn't show**: the code that **prints the bytes incorrectly** (please read about signedness of `char`) – Antti Haapala -- Слава Україні Jan 09 '18 at 20:48

1 Answers1

2

Am I using fwrite wrong?

No, you are using it correctly. Ergo, the problem with the result has to do either with the data you are writing or the stream you are writing it to.

Consider this complete program, adapted from your original code sample:

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

struct part{
    int num;
    int qoh;
    char *name;
    struct part *next;
};

int main(void) {
    struct part sp = { 199, 3, "Foo" };
    FILE *fp = fopen("out", "wb");

    for (struct part *p = &sp; p != NULL; p = p->next) {
        fwrite(&(p->num), sizeof(int), 1, fp);
        fwrite(&(p->qoh), sizeof(int), 1, fp);
        fwrite(p->name, sizeof(char), strlen(p->name) + 1, fp);
    }

    fclose(fp);

    return 0;
}

This would be a reasonable MCVE, except for the fact that it does not in fact reproduce the error for me. Here's a hex dump of the resulting output:

c7 00 00 00 03 00 00 00 46 6f 6f 00

From this you can see that my machine uses little-endian representation for its ints, but also that it does not produce mangled integers such as you describe.

Having answered your basic question, I'm not inclined to sort through your relatively substantial code to figure out where and how the problem arises. I still recommend the exercise of reducing that to an MCVE, however, as that has a decent chance of helping you discover the nature of the problem for yourself, or at least the key statements involved in it.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thanks for the help. I'm fairly new. Strangely, I see this when i run yours: ff ff ff c7 3 0 0 0 46 6f... And if I load it in, I get -57. – Trace Myers Jan 09 '18 at 20:21
  • @TraceMyers What do you mean "I load it" ? you never give code that load your file. How do you look the bytes of your files ? – Stargateur Jan 09 '18 at 20:26
  • @TraceMyers, If my program produces that output for you then something is pretty wrong. Either your C implementation is non-conforming, or your output is being mangled after the fact, or whatever mechanism you are using to examine the (binary) output is misleading you. I find it particularly suspicious that the output you present appears to be inconsistent with respect to the endianness of `int`, though I suppose you might have transcribed it incorrectly. – John Bollinger Jan 09 '18 at 20:29
  • I must be reading it wrong both in the dump and in the main program. – Trace Myers Jan 09 '18 at 20:32
  • Well, @TraceMyers, that is part of why we ask for an MCVE. By the way, what big-endian platform are you testing this on? – John Bollinger Jan 09 '18 at 20:34
  • I can confirm that the output file contains `c7 00 00 00 03 00 00 00 46 6f 6f 00`. @TraceMyers which compiler are you using? Have you another compiler and have you tried the other one? – Pablo Jan 09 '18 at 20:39
  • It's little endian. The bad hex dump was on me. The problem was I was storing the read bytes in a signed char buffer. I'll chalk that up to 99% of stackoverflow problems being simple things the person neglects to mention. Kind of embarassing. I'll get better at asking questions. Thanks for the help. – Trace Myers Jan 09 '18 at 20:53