NOVINKA: Začni v IT jako webmaster s komplexním akreditovaným online kurzem Tvůrce WWW stránek. Zjisti více:
NOVINKA: Staň se datovým analytikem od 0 Kč a získej jistotu práce, lepší plat a nové kariérní možnosti. Více informací:

Diskuze – Lekce 13 - Funkce s variabilním počet a typem argumentů v jazyce C

Zpět

Upozorňujeme, že diskuze pod našimi online kurzy jsou nemoderované a primárně slouží k získávání zpětné vazby pro budoucí vylepšení kurzů. Pro studenty našich rekvalifikačních kurzů nabízíme možnost přímého kontaktu s lektory a studijním referentem pro osobní konzultace a podporu v rámci jejich studia. Toto je exkluzivní služba, která zajišťuje kvalitní a cílenou pomoc v případě jakýchkoli dotazů nebo projektů.

Komentáře
Nejnovější komentáře jsou na konci poslední stránky.
Avatar
Patrik Pastor:10.9.2019 15:01
va_start(ap, fmt)

jak to, ze je druhy argument typ pointer?(adresa). V dokumentaci je druhy argumeny typu posledniho znameho typu (ale typ "adresa", je prece v jakemkoliv bytu). Rad bych chtel pochopit, jak funguje druhy argument "fmt" (typu char* - adresa na jeden byte) v teto funkci. Dik za odpoved

Avatar
DarkCoder
Člen
Avatar
DarkCoder:20.1.2024 14:15

„Napíšte funkciu, ktorá zo zadaných celých čísiel (argumentov) typu 'int' vyberie najväčšie a vráti ho. Prvé číslo stanovuje počet čísiel, z ktorých sa bude vyberať najväčšie. Počet zadaných čísiel môže byť rôzny.“

Proč ty složitosti ve funkci? Přímočaře..

#include <stdarg.h>
#include <stdio.h>

int maxInt(const unsigned count, ...);

int main(void) {
        int result1 = maxInt(5, 10, 5, 8, 20, 15);
        int result2 = maxInt(3, -5, 0, -3);
        int result3 = maxInt(1, 42);

        printf("Nejvetsi cislo: %d\n", result1);
        printf("Nejvetsi cislo: %d\n", result2);
        printf("Nejvetsi cislo: %d\n", result3);

        return 0;
}

int maxInt(const unsigned count, ...) {
        va_list args;
        int max, current;

        va_start(args, count);

        max = va_arg(args, int);

        for (unsigned i = 1; i < count; ++i) {
                current = va_arg(args, int);
                if (current > max) {
                        max = current;
                }
        }

        va_end(args);

        return max;
}
Odpovědět
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Yveta Kršková:10.11.2025 13:16

Nechce se mi ani věřit, že v Céčku je zapojena tak 'nebezpečná' součástka :D
Možná bych uživatele nechala zadávat čísla po jednom, pokaždé si prověřila, co mi zadal a pokud by šlo o číslo, srovnala bych ho s dosavadním nejvyšším nalezeným číslem, které mi zadal předtím (pokud už mi nějaké zadal). Pak bych měla jistotu, že mi ta opičárna nepřepíše někde paměť :D

Odpovědět
:D :D :D
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Yveta Kršková
DarkCoder:10.11.2025 14:11

To je v C naprosto normální, C je nízkoúrovňový jazyk a spousta zodpovědnosti je na programátorovi. Ano, práce s variadickými funkcemi a stdarg.h je nebezpečná, ale mocná. Je dobré je používat s rozumem, popřípadě dobře definovat konvenci jako je to u funkcí printf() a scanf().

Ano, jsou místa kde to jde elegantně obejít. A zpracování vstupu jeden po druhém je právě tento případ. A správně si naznačila vhodné řešení. Je to jednoduché ale stále ne neprůstřelné. Ale i tvorba spojového seznamu není stoprocentní. Vždy se bude balancovat mezi jednoduchostí, bezpečností a efektivitou. V C je možné vše, ale také vše může selhat. :-)

Odpovědět
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
DarkCoder
Člen
Avatar
DarkCoder:10.11.2025 15:24

Jinak funkci maxInt() lze vylepšit o detekci žádného čísla k porovnání a validní paměti pro výsledek. Stejně tak aby indikovala zda vše proběhlo v pořádku či nastala chyba.

int maxInt(const unsigned count, int *result, ...) {
    if (count == 0) return 1;       // Žádné číslo k porovnání
    if (result == NULL) return 2;   // Ukazatel result je NULL

    va_list args;
    va_start(args, result);

    int max = va_arg(args, int);
    for (unsigned i = 1; i < count; ++i) {
        int current = va_arg(args, int);
        if (current > max) max = current;
    }

    va_end(args);

    *result = max;
    return 0;
}

Kompilátor stále ale nemůže detekovat validní typy argumentů ...

Takže:
Pečlivě dokumentovat funkci, že přijímá pouze int. (Moc nepomůže :D)
Používat wrapper funkce, která typově kontroluje vstup před zavoláním variadické funkce.

Alternativa: nepoužívat variadické funkce, místo toho předat pole int a jeho délku.

Odpovědět
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovídá na DarkCoder
Yveta Kršková:13.11.2025 15:45

Ale DC, to byla ironie, přijmout od uživatele jeden údaj za druhým a nikoliv všechny naráz a důkladně si ověřovat, co zadal, nebo mu omezit možnosti zadávání, je přece standard pro každé uživatelské rozhraní. Pokud nám přicházejí opakovaně výsledky měření nějakého přístroje, ty ukládáme a vypočítáváme např. odchylku měření, nebo změnu koordinátu ukazatele, postupujeme zase jinak.
Jedna věc je, když si v úloze hrajeme, a jiná, když řešíme opravdu skutečný praktický příklad a píšeme pro někoho program.

Odpovědět
:D :D :D
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Yveta Kršková
DarkCoder:13.11.2025 15:56

To ano, postupy se liší dle situace.. efektivita a důslednost přesto nepřechází do pozadí.. A to ať už je to hraní si nebo ostrý program.. Ale vím jak si to zamýšlela.. :-)

Odpovědět
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
DarkCoder
Člen
Avatar
DarkCoder:17.11.2025 15:21

Existují i jiné způsoby práce s variadickými funkcemi než předávání počtu argumentů předem. Jedním z nejčastějších je použití tzv. sentinelu.

Sentinel je speciální hodnota vložená mezi argumenty, která slouží jako zarážka a říká:

„Od této hodnoty dál už žádné další argumenty nepokračují.“

Je to čistá konvence: samotný jazyk C nemá žádný mechanismus, jak určit konec variadické části, takže hodnotu poznávacího znamení si musí definovat samotná funkce.

Mezi nejčastěji používané sentinely patří:

NULL — ideální pro ukazatele,
speciální hodnota enum (např. TOKEN_END),
integer mimo doménu běžných hodnot (např. -1),
tzv. tagový systém (páry „typ–hodnota“ zakončené END tagem).

Příklad:

Vytvořme funkci, která vypíše libovolný počet řetězců, dokud nenarazí na NULL:

void print_strings(const char *first, ...) {
    va_list ap;
    va_start(ap, first);

    const char *s = first;
    while (s != NULL) {
        puts(s);
        s = va_arg(ap, const char *);
    }

    va_end(ap);
}

a volání:

print_strings("Hello", "world", "C", NULL);

Funkce postupně čte všechny stringy, dokud nenarazí na sentinel NULL, který ukončí zpracování variadických argumentů.

Odpovědět
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Nejnovější komentáře jsou na konci poslední stránky.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 8 zpráv z 18.