0

The user specifies the number of lines in the output in the arguments (as the size of the page in pagination), by pressing the key he gets the next lines. How it works now: Let's say the user chose to receive 1 row at a time:

first string

first string second string

first string second string third string

struct result {
        char part[32768];
        int is_end_of_file;
};

struct result readLines(int count) {
        int lines_readed = 0;
        struct result r;
        if (count == 0) {
                count = -1;
        }

        while (count != lines_readed) {
                while (1) {
                        char sym[1];
                        sym[0] = (char) fgetc(file);


                        if (feof(file)) {
                                r.is_end_of_file = 1;
                                return r;
                        }

                        strcat(r.part, sym);

                        if (*"\n" == sym[0]) {
                                break;
                        }
                }
                lines_readed++;
        }

        return r;

}


int main(int argc, char *argv[]) {
        file = fopen(argv[1], "r");

        while (1) {
                struct result res = readLines(atoi(argv[2]));
                printf("%s", res.part);
                if (res.is_end_of_file) {
                        printf("\nEnd of file!\n");
                        break;
                }

                getc(stdin);
        }
        closeFile();
        return 0;
}

I know that when I define a struct in the readLines function, it is already filled with previous data. Forgive me if this is a dumb question, I'm a complete newbie to C.

  • 1
    *"I know that when I define a struct in the readLines function, it is already filled with previous data."* - that is wrong. There is nothing that would require or guarantee this – UnholySheep Oct 22 '22 at 19:58
  • I tried to output data to the console immediately after creating an instance of the structure and there was already data – user17252149 Oct 22 '22 at 20:00
  • 1
    Since you didn't show the relevant code for this, I can only assume that you have printed *uninitialized* data, which is in itself *undefined behavior* - the code may print *anything*, including data that was written in a previous invocation of the function – UnholySheep Oct 22 '22 at 20:01
  • 1
    "I tried to... and..." *You got lucky*. There is no guarantee it will happen next time. – n. m. could be an AI Oct 22 '22 at 20:02
  • I didn’t quite understand you ... I don’t transfer the previous data there, how can they be there? I output the data like this: ```printf (r.part)``` after ```struct result r;``` – user17252149 Oct 22 '22 at 20:04
  • 1
    So you didn't assign any values to `r.part` - so it contains *indeterminate values* - meaning you have absolutely no guarantee what data is there. It will contain "random values" – UnholySheep Oct 22 '22 at 20:10
  • I print ```printf(r.part);``` at the end of the function and it is filled with both new and previous data. There is a crooked solution - to put ```strcpy(r.part, "");``` after ```struct result r;```But something more correct would be better. – user17252149 Oct 22 '22 at 20:15
  • A correct solution is to write code that doesn't invoke *undefined behavior*. Your assumption is completely wrong and can break at the slightest change in the code (or even on a different compiler). `strcat(r.part, sym);` is also wrong, since `sym` is not a null-terminated string – UnholySheep Oct 22 '22 at 20:17
  • Can anyone explain how the old data gets there? For me, as a person who writes in python, this is completely incomprehensible. – user17252149 Oct 22 '22 at 20:20
  • 1
    Here is a little example. You frequent a certain hotel. One day you check in, get a room, spend a day there, and forget your phone in the desk drawer. In a couple of days you return, check in, get a room, and lo and behold, you find a phone in the desk drawer! Can you explain this? Does it mean there always be a phone in the desk drawer whenever you check into an hotel? – n. m. could be an AI Oct 22 '22 at 20:23
  • But I'm creating a new instance, doesn't this mean that a new cell in memory with a new address should be allocated for it? – user17252149 Oct 22 '22 at 20:26
  • 1
    Should you be getting a brand new, never used room each time you check into a hotel? Why or why not? – n. m. could be an AI Oct 22 '22 at 20:31
  • Well, apparently it's too complicated for me yet) Thanks for the help everyone) – user17252149 Oct 22 '22 at 20:42
  • There is nothing complicated in there. If you don't assign a value to a variable, then what the variable contains is *garbage* (the polite term is "indeterminate value", but it means "garbage"). It may contain zeros. It may contain a Swahili translation of Sonnet 60. It may even contain a value you recently left in a similar variable. It is still garbage. – n. m. could be an AI Oct 23 '22 at 04:51

1 Answers1

0

I'm not sure what is the question here, however I'll do my best to address what I understand. I assume the problem lies somewhere around the "previous data" you mentioned in the title and in the comments to the question.

Let's first set an example program:

#include <stdio.h>

struct result {
    char part[10];
};

int main (int argc, char *argv[]) {
    struct result r;
    printf(r.part);
    return 0;
}

The variable r has a block scope, so it has automatic storage duration. Since it has automatic storage duration, and no initializer is provided, it is initialized to an indeterminate value (as mentioned by UnholySheep and n. 1.8e9-where's-my-share m. in the comments to the question). I don't yet get all the C intricacies, but based on this, I guess you cannot rely on what the value of r will be.

Now, in the comments to the question you try to understand how is it possible that you can access some data that was not written by the current invokation of your program. I cannot tell you exactly how is that possible, but I suspect it is rather platform-specific than C-specific. Maybe the following will help you:

Going further, in the line

printf(r.part);

first we try to access a member part of r, and then we call printf with the value of this member. Accessing a variable of an indeterminate value results in undefined behavior, according to this. So, in general, you cannot rely also on anything that happens after invoking r.part (it doesn't mean there is no way of knowing what will happen).

There is also another problem with this code. printf's first parameter is interpreted as having the type const char *, according to man 3 printf, but there is provided a variable that has the type struct result. Indeed, there is produced the following warning when the code is compiled with gcc with the option -Wformat-security:

warning: format not a string literal and no format arguments [-Wformat-security]

Unfortunately, I don't know C well enough to tell you what precisely is happening when you do such type mismatch in a function call. But as we know that there already happened undefined behavior in the code, this seems less important.

As a side note, a correct invokation of printf could be in this case:

printf("%p", (void *)r.part);

r.part is a pointer, therefore I use the %p conversion specifier, and cast the value to (void *).

user20276305
  • 95
  • 1
  • 7