• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wczytaj, dodaj i wyświetl

0 głosów
572 wizyt
pytanie zadane 30 marca 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)

Hej :)

Mam problem z usprawnieniem mojego programu do pewnego zadania.

Treść jest taka:

Napisz program, który pobierze od użytkownika nazwę pliku, a następnie odczyta i wyświetli na ekranie sumę liczb z pliku. Liczby w pliku oddzielone będą białym znakiem (np. spacja, enter, tabulator).

Jeżeli podany przez użytkownika plik nie istnieje program powinien wyświetlić komunikat Couldn't open file i zakończyć działanie z kodem błędu 4. Jeżeli w plik będą znajdowały się dane inne niż liczby, program powinien wyświetlić komunikat File corrupted i zakończyć działanie z kodem błędbu 6

Jeżeli udało się obliczyć sumę liczb, zawartych w podanym pliku, program powinien ją wyświetlić zwrócić wartość 0.

Przykładowa interakcja z programem (dla pliku wejściowego text.txt):

Podaj sciezke do pliku:⏎
text.txt⏎
Suma wczytanych liczb wynosi: 200
Przykładowa interakcja z programem - brak pliku:

Podaj sciezke do pliku:⏎
diestartyellowsubtractbloc⏎
Couldn't open file⏎
Przykładowa interakcja z programem - uszkodzony plik (zawiera cokolwiek innego, niż liczby):

dawajta sciezke do pliku:⏎
question.txt⏎
File corrupted
Uwaga

W programie nie wolno używać funkcji alokujacych pamięć.
W programie można zadeklarować tylko tablice na 30 znaków (do przechowywania nazw plików). Deklaracja musi wyglądać następująco: nazwa_zmiennej[31];.
W programie nie wolno używać operatora [].

A oto mój kod:

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

int main()
{
    char tab[31]={0};
    char input[31]={0};
    char *tab_i=&(*(tab+0)), *input_i=&(*(input+0));



    int i;
    printf("Podaj sciezke do pliku\n");
    scanf(" %31[^\n]", input_i);
    for(i=0; i<30; i++)
    {
        *(tab_i+i)=*(input_i+i);
    }

    FILE *f= fopen(tab_i,"rb");
    if(f==NULL)
    {
        printf("Couldn't open file");
        return 4;
    }

    int suma = 0;
    char znak;
    int znak_int;


    while(fread(&znak,1,1,f) != 0 )
    {
        if(znak>=48 && znak<=57)
        {

        }
        else if(znak==' ' || znak=='\n' || znak=='\t' || znak=='\0' || znak==13 || znak=='-')
        {

        }
        else
        {
            //printf("%c",znak);
            fclose(f);
            printf("File corrupted");
            return 6;
        }

        fscanf(f,"%d",&znak_int);
        //printf("\n%d\n",znak_int);
        suma+= znak_int;

        ;
    }
    printf("%d",suma);
    fclose(f);
    return 0;
}

Przy sprawdzaniu zadania na testach zauważyłem, że wyskakuję ciągle niepoprawne wartości (sumy liczb z mojego programu różnią się nieznacznie od tego co powinno wychodzić na testach, ale jednak się różni). Zauważyłem między innymi problem w przypadku pojawienia się pustej linijki w moim pliku tekstowym. Wtedy najczęściej dochodzi do dziwnych pomyłek. Np. dla tak zapisanych przeze mnie danych w pliku tekstowym:

2

3 
5

3

1 3

policzyło ostateczną wartość jako...18. Tak więc czy jest coś, o czym zapomniałem podczas wykonywania przeze mnie tego zadania? Jeżeli tak, to jak mogę to zaimplementować? 

komentarz 30 marca 2020 przez j23 Mędrzec (195,220 p.)

Dlaczego nie użyjesz fscanf do czytania liczb?

komentarz 30 marca 2020 przez Hubertius Bywalec (2,970 p.)

@j23 No teoretycznie używam pod sam koniec pętli:

fscanf(f,"%d",&znak_int);

 

komentarz 30 marca 2020 przez j23 Mędrzec (195,220 p.)

To co tam fread robi?

komentarz 30 marca 2020 przez Hubertius Bywalec (2,970 p.)
edycja 30 marca 2020 przez Hubertius

fread de facto czyta znak po znaku aż w końcu dojdzie do końca pliku i zwróci wartość mniejszą od count (czyli w tym przypadku zero). Czyli mogę na spokojnie warunek wykonywania pętli zastąpić fscanf?

Zapisałem coś w tym stylu:

while(fscanf(f,"%d",&znak_int)==1)
    {
        suma += znak_int;
    }
    printf("%d",suma);

I teraz zlicza mi wszelkie znaki, niezależnie od tego czy są spacje i entery-y pomiędzy liczbami. Pozostaje jednak tylko pytanie jakie zabezpieczenie mogę zrobić na przypadek "File corrupted"?

EDIT

Udało mi się poprawnie wykonać to zadanie. Oto ostateczny kod:

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

int main()
{
    char tab[31]={0};
    char input[31]={0};
    char *tab_i=&(*(tab+0)), *input_i=&(*(input+0));



    int i;
    printf("Podaj sciezke do pliku\n");
    scanf(" %31[^\n]", input_i);
    for(i=0; i<30; i++)
    {
        *(tab_i+i)=*(input_i+i);
    }

    FILE *f= fopen(tab_i,"rb");
    if(f==NULL)
    {
        printf("Couldn't open file");
        return 4;
    }

    int suma = 0;
    int znak_int;
    char znak;
    while(fread(&znak,1,1,f) != 0)
    {
        if(znak>=48 && znak<=57)
        {

        }
        else if( znak==13 || znak=='\t' || znak=='\0' || znak=='-' || znak==' ' || znak=='\n')
        {

        }
        else
        {
            fclose(f);
            printf("File corrupted");
            return 6;
        }
    }
    fseek(f,0,SEEK_SET);

    while(fscanf(f,"%d",&znak_int)==1)
    {
        suma += znak_int;
    }
    printf("%d",suma);
    fclose(f);
    return 0;
}

 

komentarz 30 marca 2020 przez j23 Mędrzec (195,220 p.)

@Hubertius,  zamiast tej pierwszej pętli while testującej, czy nie ma innych znaków, po prostu sprawdzaj co zwraca fscanf - jeśli zwróci zero, to znaczy, że napotkała na coś, co nie jest liczbą.

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
0 odpowiedzi 278 wizyt
pytanie zadane 31 marca 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)
0 głosów
1 odpowiedź 942 wizyt
0 głosów
1 odpowiedź 797 wizyt
pytanie zadane 4 kwietnia 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)

93,695 zapytań

142,613 odpowiedzi

323,225 komentarzy

63,226 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...