Nieokreślona ilość argumentów funkcji

Odpowiedz Nowy wątek
2011-08-20 14:05
Cypis
0

Jestem bardzo początkującym w temacie programowania, uczę się od kilku tygodni. Po kilku krokach do przodu pojawiła się ściana której nie mogę pokonać. Liczę na Waszą pomoc.

Od rana walczę z zadaniem w którym jest funkcja która pobiera dziesięć (lub mniej) elementów z klawiatury i z których znajduje maksimum. Znalezienie maksimum nie jest problemem, problemem jest podawanie różnej liczby argumentów. Na tym etapie nauki jestem w stanie zrobić to zadanie ale tylko dla wprowadzania maksymalnej ilości elementów (w parze liczba + \n). Natomiast nie wiem jak zrobić żeby program pozwolił mi na wpisaniu kolejnego elementu funkcji po kliknięciu klawisza '\n' bez podania liczby.
W tej chwili nie mam kodu który mógłbym wkleić, bo wykasowałem moje wszystkie próby.

Próbowałem rozwiązać problem za pomocą pętli do..while - wyglądało to mniej więcej tak:

    do
    {
        for (i=0;i<9;i++)
    {
        printf("\nPodaj %d liczbe: \n",i+1);
 
            scanf("%d",&t[i]);
    }
    } while (c=getchar()!='\n');

Próbowałem użyć funkcji gets ale nie bardzo mogłem sobie z tym poradzić, zupełnie nic nie wychodziło. :(

Pozostało 580 znaków

2011-08-20 14:09
Kumashiro
0

A co Ci się złego działo z gets()?
Wczytujesz linię przez fgets(), splitujesz po białych znakach i konwertujesz na liczby.

Pozostało 580 znaków

2011-08-20 14:24
0

Dzięki za odpowiedź, w międzyczasie założyłem konto - więc odpowiadam pod innym NICK.

Nie pamiętam co złego wyskakiwało z gets, prawdopodobnie jakiś błąd składni. Spróbuje wieczorem z fgets, mam nadzieję że dam radę ze "splitowaniem" i konwertowaniem na liczbę - w razie czego będę zadawał kolejne pytania. Jeszcze raz dzięki.

Pozostało 580 znaków

2011-08-20 14:52
Kumashiro
0

Tutaj masz znacznie ułatwione zadanie. Podpowiem Ci jedną rzecz: splitowanie i konwersję możesz zrobić za jednym zamachem (ale nie w jednym kroku!) dzięki drugiemu argumentowi do strtol(). Happy coding :)

Pozostało 580 znaków

2011-08-20 19:45
0

A co Ci się złego działo z gets()?

Z gets działo się to złego, że jest evil, zue, niedobre. NIE UŻYWAĆ.
Dlaczego? Bo zgodnie ze standardem, ma prawo wysłać twoje nagie fotki na fejsbóka.

http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1049157810&id=1043284351

Pozostało 580 znaków

2011-08-21 12:23
0
Kumashiro napisał(a)

Tutaj masz znacznie ułatwione zadanie. Podpowiem Ci jedną rzecz: splitowanie i konwersję możesz zrobić za jednym zamachem (ale nie w jednym kroku!) dzięki drugiemu argumentowi do strtol(). Happy coding :)

Udało mi się zrobić zadanie, nie było łatwo ;) zajęło to trochę czasu ale działa! Byłbym wdzięczny jakby ktoś bardziej doświadczony zerknął czy kod jest w miare poprawny, czy nie można go jakoś udoskonalić. Za wszystkie uwagi i sugestie z góry dziękuję, będą pomocne w kolejnym etapie nauki :)

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int max[10],i,pom,mx;
    char c[100],*tmp;
 
    for (i=0;i<9;i++)
    {
        max[i]=0;
    }
 
    for (i=0;i<9;i++)
    {
        // wczytywanie liczb
        printf("\nPodaj %d liczbe: \n",i+1);
        fgets(c,100,stdin);
 
        //przetworzenie stringa na liczbe i wpisanie jej do tablicy
        pom=strtol(c,&tmp,10);
        max[i]=pom;
 
        if (max[i]==0)
            i=9;
    }
 
    mx=max[0];
    for(i=0;i<9;i++)
    {
        if (mx<max[i])
            mx=max[i];
    }
 
    printf("\n\nMaksymalna liczba to: %d",mx);
 
    fflush(stdout);
    getchar();
    getchar();
    return 0;
}

Pozostało 580 znaków

2011-08-21 12:44
Kumashiro
0
Rumburak napisał(a)
int main()

Piszesz w C, zatem:

int main(void)
Rumburak napisał(a)
for (i=0;i<9;i++)
{
max[i]=0;
}

Użyj memset() do wyzerowania całego bloku pamięci:

memset(max, 0, sizeof(max));

lub zainicjuj od razu tablicę zerami:

int max[10] = { 0, };

Masz dziesięcioelementową tablicę, a zerujesz tylko 9 elementów.

Rumburak napisał(a)
for (i=0;i<9;i++)
{
// wczytywanie liczb
printf("\nPodaj %d liczbe: \n",i+1);
fgets(c,100,stdin);

To samo tutaj. Wczytujesz tylko 9 liczb, a miałeś wczytać 10. Masz zły warunek.
W przypadku stdin błędy odczytu są mało prawdopodobne, ale warto pamiętać o sprawdzeniu czy fgets() nie zwrócił NULL.

Rumburak napisał(a)
//przetworzenie stringa na liczbe i wpisanie jej do tablicy
pom=strtol(c,&tmp,10);
max[i]=pom;

Nie sprawdzasz błędów!
Nie potrzebujesz też zmiennej pom.

Rumburak napisał(a)
if (max[i]==0)
i=9;
}

A cóż to?

Rumburak napisał(a)
mx=max[0];
for(i=0;i<9;i++)
{
if (mx<max[i])
mx=max[i];
}

Mało wydajne. Test możesz przeprowadzić w pętli wczytującej i przechowywać tylko wartość maksymalną skoro do niczego innego nie używasz tablicy max. Jest ona zbyteczna.

Rumburak napisał(a)
fflush(stdout);

To jest zbędne.

Ogólnie dobrze, ale jeszcze nad tym popracuj :)

Pozostało 580 znaków

2011-08-21 13:06
0
Kumashiro napisał(a)
Rumburak napisał(a)
int main()

W przypadku stdin błędy odczytu są mało prawdopodobne, ale warto pamiętać o sprawdzeniu czy fgets() nie zwrócił NULL.

Rumburak napisał(a)
//przetworzenie stringa na liczbe i wpisanie jej do tablicy
pom=strtol(c,&tmp,10);
max[i]=pom;

Nie sprawdzasz błędów!

To prawda, muszę pomyśleć w jaki sposób sprawdzić czy nie została wpisana litera lub "czy fgets() nie zwrócił NULL", może jakieś wskazówki? :)

Ogólnie dobrze, ale jeszcze nad tym popracuj :)

Poprawione wg wskazówek, teraz trochę lepiej (a na pewno krócej) Dzięki!

#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
    int i,pom,mx=0;
    char c[100],*tmp;
 
    for (i=0;i<10;i++)
    {
        // wczytywanie liczb
        printf("\nPodaj %d liczbe: \n",i+1);
        fgets(c,100,stdin);
 
        //przetworzenie stringa na liczbe
        pom=strtol(c,&tmp,10);
 
        if (mx<pom)
            mx=pom;
 
        if (pom==0)
            i=10;
    }
 
    printf("\n\nMaksymalna liczba to: %d",mx);
 
    getchar();
    getchar();
    return 0;
}

Pozostało 580 znaków

2011-08-21 13:17
Kumashiro
0
<quote=rumburak> ```c if (pom==0) i=10; } ``` <quote> Fuj. Co to jest? Po pierwsze, jeśli chcesz zakończyć pętlę, użyj instrukcji `break`. Po drugie, ten kod uniemożliwia podanie wartości `0` jako pełnoprawnej danej, gdyż powoduje ona zaprzestanie wczytywania. OK, poniżej masz to zadanie z pełną obsługą błędów. ```c #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { long int value, max = 0; char *endptr, input[128]; int i; errno = 0; endptr = input; for ( i = 0; i < 10; i++ ) { if ( fgets(input, sizeof(input) - 1, stdin) == NULL ) { break; /* Ctrl-D przerywa wprowadzanie danych wcześniej */ }; value = strtol(input, &endptr, 10); if ( input == endptr || ((*endptr != '\n') && (*endptr != '\0')) ) { fprintf(stderr, "Invalid input: %s\n", input); return 2; } else if ( errno != 0 ) { fprintf(stderr, "Value error: %s\n", strerror(errno)); return 3; }; if ( value > max ) max = value; }; fprintf(stdout, "Max: %li\n", max); return 0; } ```
Coś mi się źle zacytowało... sorki - Kumashiro 2011-08-21 13:17

Pozostało 580 znaków

2011-08-21 13:34
0
<quote=kumashiro><quote=rumburak> ```c if (pom==0) i=10; } ``` > Fuj. Co to jest? > Po pierwsze, jeśli chcesz zakończyć pętlę, użyj instrukcji `break`. > Po drugie, ten kod uniemożliwia podanie wartości `0` jako pełnoprawnej danej, gdyż powoduje ona zaprzestanie wczytywania. Nie można się nie zgodzić z uwagami, ale zamieszczony przez Ciebie kod wywala się jak nie wpiszę żadnego znaku i potwierdzę enterem (kompiluje w QT pod windowsem - jeżeli ma to jakieś znaczenie?). :/ Poza tym, to co napisałeś to bardzo czarna magia. Nic nie rozumiem, nawet nie wiem o co dopytywać :)

Pozostało 580 znaków

2011-08-21 14:48
Kumashiro
1
Rumburak napisał(a)

Nie można się nie zgodzić z uwagami, ale zamieszczony przez Ciebie kod wywala się jak nie wpiszę żadnego znaku i potwierdzę enterem

Co rozumiesz przez "wywala się"? U mnie wypisuje komunikat błędu, tak jak powinien.

Rumburak napisał(a)

(kompiluje w QT pod windowsem - jeżeli ma to jakieś znaczenie?). :/

Qt to jest framework, nie kompilator. System operacyjny nie powinien mieć tu znaczenia.

Rumburak napisał(a)

Poza tym, to co napisałeś to bardzo czarna magia. Nic nie rozumiem, nawet nie wiem o co dopytywać :)

OK, to teraz z tłumaczeniem:

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

Includy... najwyraźniej

int  main(void)
{
    long int    value, max = 0;
    char        *endptr, input[128];
    int         i;

Deklaracje. Zmienna value przechowuje skonwertowaną wartość, max - maksymalną wartość, pod endptr funkcja strtol() zapisze wskaźnik do miejsca, na którym kończy się konwersja, input to nasz bufor (można go zmniejszyć, bo 128 bajtów to trochę przydużo), zaś i posłuży nam do iteracji. Zmienną max od razu inicjujemy wartością 0. Jeśli dopuszczamy wartości ujemne, powinniśmy ją zainicjować najmniejszą wartością, jaką na danej platformie jest w stanie przechować typ long int.

    errno = 0;
    endptr = input;

Najpierw zerujemy zmienną globalną errno. Teoretycznie nie jest to wymagane, gdyż nigdzie przed tą linią nie wywołujemy nic co mogłoby ją ustawić, ale nie zaszkodzi. Linia endptr = input jest tu niepotrzebna (sorry, część kodu skopiowałem z mojego innego programu i zostały śmieci).

    for ( i = 0; i < 10; i++ ) {
        if ( fgets(input, sizeof(input) - 1, stdin) == NULL ) {
            break; /* Ctrl-D przerywa wprowadzanie danych wcześniej */
        };

Wchodzimy do pętli for, która zrobi 10 obrotów. Przy każdej iteracji wczytujemy z stdin lnię tekstu, o długości równej maksymalnej objętości naszego bufora (i ponownie został śmieć; - 1 jest tutaj niepotrzebny, ale nie wadzi). Jeśli user nie wpisze nic, lecz wdusi kombinację Ctrl-D (fgets() zwróci NULL), iterowanie zostanie przerwane. Uwaga! Wpisanie pustej linii (wciśnięcie ENTER) nie łapie się do tego warunku, gdyż w danych wejściowych będzie znak nowej linii.

        value = strtol(input, &endptr, 10);

Przeprowadzamy konwersję ze cstringa input, podstawa 10. Wynik ląduje w zmiennej value. Wskaźnik endptr będzie wskazywał pierwszą pozycję z input, na której znajduje się bajt nie należący do wartości liczbowej. Np. jeśli spróbujemy skonwertować "123abc", wartością zwróconą będzie liczba 123, zaś endptr będzie wskazywał na a. Zaraz wykorzystamy to do kontroli błędów.

        if ( input == endptr || ((*endptr != '\n') && (*endptr != '\0')) ) {
            fprintf(stderr, "Invalid input: %s\n", input);
            return 2;

Jeśli wskaźnik endptr wskazuje na pierwszy bajt danych wejściowych (input == endptr), to znaczy że cstring rozpoczyna się od danych, których nie można przekonwertować na liczbę. Jeśli wskaźnik endptr nie wskazuje ani na znak nowej linii, ani na bajt zerowy, to znaczy że w cstringu po liczbie znajdują się jakieś inne znaki. Wszystkie te przypadki traktujemy jako błąd, gdyż nie są to prawidłowe dane wejściowe. Przykłady takich przypadków:

"abcd\n\0"
"123abcd\n\0"
"123 \n\0"
"\n\0"
        } else if ( errno != 0 ) {
            fprintf(stderr, "Value error: %s\n", strerror(errno));
            return 3;
        };

Jeśli konwersja nie może być przeprowadzona z innego powodu (np. przekroczenie zakresu), barfujemy i kończymy pracę.

        if ( value > max )
            max = value;
    };

Sprawdzamy, czy odczytana wartość jest większa od zapamiętanej wartości maksymalnej i jeśli jest to prawda, zapisujemy ją jako największą.

    fprintf(stdout, "Max: %li\n", max);
    return 0;
}

Po wyjściu z pętli printujemy wynik i kończymy pracę bez błędu.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0