C - Работа с fopen, fclose, fputc и др

Накарах този код най-накрая да работи с един аргумент в моя команден ред, т.е. един файл, с който да работи, въпреки че проектирах кода с концепцията той да работи с неограничен брой файлове. Това, което прави, е да вземе някои X на брой текстови файлове, съдържащи думи, разделени с интервали, и заменя интервалите с \n, като по този начин създава списък с думи. Въпреки това успешно завършва първия аргумент, просто игнорира втория.

Друг малък проблем изглежда, че той също отпечатва някаква боклук буква в края, Y с две точки над него; Предполагам някакъв EOF символ, но изглежда не мога да спра това да се случва!

int main(int argc, char** argv) {
    FILE *fpIn, *fpOut;
    int i, j;
    j = 1;
    char c;
    char myString[256];

    printf("%d", argc);
    printf("\n");
    printf("The following arguments were passed to main(): ");
                for(i=1; i<argc; i++) printf("%s ", argv[i]);
    printf("\n");

    while(argc--) {
        for(i = 1; i < argc; i++) {
            fpIn = fopen(argv[j], "rb");
            snprintf(myString, 256, "%s~[%d]", argv[j], i);
            fpOut= fopen(myString, "wb");
            while (c != EOF) {
                c = fgetc(fpIn);
                if (isspace(c)) 
                    c = '\n';
                fputc(c, fpOut );
            }
            j++;
        }
    }
    return 0;
}

person PnP    schedule 27.12.2011    source източник
comment
възможен дубликат на Работа с текстови файлове две. Вашият приет отговор на този въпрос обяснява защо получавате този допълнителен боклук. Вашият код продължава да е неправилен в този въпрос.   -  person Greg Hewgill    schedule 28.12.2011
comment
Да, това беше предишната ми публикация, но постигнах известен напредък, но обикновено не получавам отговори на по-стари публикации, така че реших, че мога да направя друга :)   -  person PnP    schedule 28.12.2011
comment
Наистина не разбирам защо, ако съм честен   -  person PnP    schedule 28.12.2011
comment
Накратко, разгледайте правилото: Никога не записвайте стойността EOF във файл. Сега, как може да се случи това във вашия код? (Това е така, ще трябва да разберете как и да го поправите.)   -  person Greg Hewgill    schedule 28.12.2011
comment
Въпреки това все още не мога да го накарам да работи за множество аргументи:/   -  person PnP    schedule 28.12.2011


Отговори (1)


Функциите getchar(), getc() и fgetc() (или макросите) връщат int, а не char.

Трябва да използвате:

int c;

while ((c = fgetc(fpIn)) != EOF)
{
    if (isspace(c))
        c = '\n';
    fputc(c, fpOut);
}

Помисли за това; функциите трябва да могат да връщат всякакви валидни char и EOF (което е различно от всяка валидна char стойност. Така че по дефиниция върнатата стойност не може да бъде char...

Какво се случва, ако използвате char?

  • Вашият оригинален код не е инициализирал c преди да го тества (така че цикълът може да прекъсне рано).
  • Вашият код не тества c веднага след прочитане на EOF (така че може да отпечата ненужен знак, често ÿ, МАЛКА ЛАТИНИЦА Y С ДИАЕРЕЗИС, U+00FF).
  • Ако вашият тип char е без знак, никога няма да видите EOF.
  • Ако вашият тип char е подписан, някои валидни знаци (често отново ÿ) ще бъдат изтълкувани погрешно като EOF.

Въпреки това все още не мога да го накарам да работи за множество аргументи.

Проблемът там е двойният цикъл, който изпълнявате:

int i, j;
j = 1;

while (argc--)
{
    for (i = 1; i < argc; i++)
    {
        fpIn = fopen(argv[j], "rb");
        ...process fpIn...
        j++;
    }
}

Да предположим, че извиквате командата с две имена на файлове; след това argc == 3.

След първото преминаване на цикъла while, argc == 2. След това правите for цикъл с i, приемащ стойност 1; отваряте argv[1] (защото j == 1). Вие обработвате този файл; след това увеличете j до 2, преди също да увеличите i, също до 2. Вторият път около цикъла for, i == 2, както прави argc, така че цикълът for завършва. Цикълът while намалява argc отново до 1, но тества това 2 != 0. Цикълът for обаче задава i = 1 и след това прекратява, защото i == argc. Цикълът while намалява argc до 1 и се повтаря.

Можете да използвате while цикъл или for цикъл, но не са ви необходими и двата.

И така, или:

for (i = i; i < argc; i++)
{
    ...process argv[i]...
}

Or:

while (--argc > 0)
{
    ...process *++argv...
}

Бих използвал цикъла for.

person Jonathan Leffler    schedule 28.12.2011
comment
Благодаря, добавих проверка, за да видя дали е EOF в текущия ми цикъл, if ( c == EOF) {break;} Това го поправи! - person PnP; 28.12.2011
comment
Въпреки това все още не мога да го накарам да работи за множество аргументи:/ - person PnP; 28.12.2011