Znovu volání funkce s argumentem

Místo pro dotazy a rady ohledně programovacích jazyků (C++, C#, PHP, ASP, Javascript, VBS..) a tvorby webových stránek

Moderátor: Mods_senior

Uživatelský avatar
Zeppelin
Level 3.5
Level 3.5
Příspěvky: 939
Registrován: říjen 07
Pohlaví: Muž
Stav:
Offline

Znovu volání funkce s argumentem

Příspěvekod Zeppelin » 05 črc 2011 12:37

Zdar, nevím jak otevřít to téma co jsem včera uzavřel ale stejně jsem problém nevyřešil.Přikládám origo kód který nefunguje :D

Kód: Vybrat vše

int HIGH = 1;   // Počáteční hodnoty
int LOW  = 5000;

void main(void)
{

   for(;;)
    {
       Rising_one(HIGH, LOW); 
    }
}

int Rising_one(int HIGH, int LOW) 
{
   if(HIGH < 4999)
   {
      BLUE_OFF;
      GREEN_ON;
      DelayUs(LOW);
      BLUE_ON;
      GREEN_OFF;
      DelayUs(HIGH);
      HIGH++;
      LOW--;
   }
      else
      Rising_two(HIGH, LOW);
}

int Rising_two(int HIGH, int LOW)
{
      HIGH = Rising_one(HIGH, LOW);  // Tady to přijme hodnoty z Rising_one
      LOW  = Rising_one(HIGH, LOW);
      if(HIGH > 2)
      {
      GREEN_OFF;
      RED_OFF;
      BLUE_ON;
      DelayUs(LOW);
      GREEN_OFF;
      RED_ON;
      BLUE_OFF;
      DelayUs(HIGH);
      HIGH--;
      LOW++;
      }
      
      else
      Rising_one(HIGH, LOW);  // Zavolá to Rising_one s hodnotama, které vzejdou z Rising_two
}

Intel Celeron G1840, 4GB RAM DDR3, MB Gigabyte H81-S2V, Asus GT610 1GB, SSD Kingston HyperX Fury 120GB, WD 500GB SATAII, Asus DVD-RW LightScribe, Fortron 350W

Jak označit téma za vyřešené
HiJackThis
Návod na údržbu systému pro začátečníky

Reklama
Uživatelský avatar
Speed_dead
Level 6
Level 6
Příspěvky: 3281
Registrován: duben 10
Bydliště: Praha
Pohlaví: Muž
Stav:
Offline
Kontakt:

Re: Znovu volání funkce s argumentem

Příspěvekod Speed_dead » 05 črc 2011 13:06

Požádej admina o odemčení starého topicu a o sloučení příspěvků.
Google ví skoro vše. Ale někdy je problém co tam napsat, aby to našlo to, co hledám.
Pokud se to nepovede, vypadne tuna nepoužitelných odkazů a nebo taky nic.

Uživatelský avatar
Zeppelin
Level 3.5
Level 3.5
Příspěvky: 939
Registrován: říjen 07
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod Zeppelin » 05 črc 2011 13:19

A jak ho požádám?
Intel Celeron G1840, 4GB RAM DDR3, MB Gigabyte H81-S2V, Asus GT610 1GB, SSD Kingston HyperX Fury 120GB, WD 500GB SATAII, Asus DVD-RW LightScribe, Fortron 350W

Jak označit téma za vyřešené
HiJackThis
Návod na údržbu systému pro začátečníky

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod faraon » 05 črc 2011 13:29

Takže ty potřebuješ aby funkce měnila předané parametry?
To jí musíš předat ukazatel, protože když předáš pouze hodnotu, pracuje se s kopiemi proměnných a původní se nemění!
K tou slouží operátory * a &, vyzkoušej tohle:

Kód: Vybrat vše

int HIGH = 1;
int LOW  = 5000;

void funkce(int* x,int* y)
     {
     ++*x;
     --*y;
     }

int main(void)
    {
    printf("%d\t%d\n",HIGH,LOW);
    funkce(&HIGH,&LOW);
    printf("%d\t%d\n",HIGH,LOW);

    return 0;
    }
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

Uživatelský avatar
Zeppelin
Level 3.5
Level 3.5
Příspěvky: 939
Registrován: říjen 07
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod Zeppelin » 05 črc 2011 14:05

Děkuju moc, už to skoro jede.... první funkce funguje dobře ale v druhé se hodnoty HIGh a LOW nemění a taky mi pak nejde zavolat první funkci z druhé tak jako na začátku.

Kód: Vybrat vše

int HIGH = 1;
int LOW  = 5000;

void main(void)
{
   for(;;)
    {
       Rising_one(&HIGH, &LOW);
    }
}

int Rising_one(int *HIGH, int *LOW)
{
   if(*HIGH < 4999)
   {
      BLUE_OFF;
      GREEN_ON;
      DelayUs(*LOW);
      BLUE_ON;
      GREEN_OFF;
      DelayUs(*HIGH);
      ++*HIGH;
      --*LOW;
   }
   
   else
   
      Rising_two(&HIGH, &LOW);

}

int Rising_two(int *HIGH, int *LOW)  // Tady se hodnoty HIGH a LOW už nemění
{
      if(*HIGH > 2)
      {
      GREEN_OFF;
      RED_OFF;
      BLUE_ON;
      DelayUs(*LOW);
      GREEN_OFF;
      RED_ON;
      BLUE_OFF;
      DelayUs(*HIGH);
      --*HIGH;
      ++*LOW;
      }
     else

          Rising_one(&HIGH, &LOW);  // Tohle háže chybu
}

Intel Celeron G1840, 4GB RAM DDR3, MB Gigabyte H81-S2V, Asus GT610 1GB, SSD Kingston HyperX Fury 120GB, WD 500GB SATAII, Asus DVD-RW LightScribe, Fortron 350W

Jak označit téma za vyřešené
HiJackThis
Návod na údržbu systému pro začátečníky

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod faraon » 05 črc 2011 15:04

První chyba: volat můžeš jen funkci kterou už překladač zná. Když ji dáš až za main(), musíš ji nejdřív deklarovat prototypem, aby překladač věděl jaké typy proměnných jí lze předávat, takže by to muselo být napsané takhle:

Kód: Vybrat vše

void funkce(int *x,int *y); /* prototyp funkce ukončený středníkem */

int main(void)
    {
    funkce(&HIGH,&LOW); /* volání funkce */
    return 0;
    }

void funkce(int *x,int *y) /* samotná funkce provádějící činnost */
     {
     ++*x;
     --*y;
     }

Totéž platí i pro vzájenou rekurzi, kterou jsi tam tak pěkně spáchal, takže i kdyby obě funkce byly před main(), tak ta co je ve zdrojáku první bude volat tu druhou v pořadí a překladač tápe. Ona to sice většina kompilátorů nějak přebere, ale vyhazuje warningy (pokud nejsou vypnuté) a výsledek může fungovat jinak než chceš!
Já proto kompiluji zásadně takhle gcc -Wall -pedantic program.c a dostávám varování i s čísly řádků na kterých si překladač není jistý. Dají se použít i další upřesňující parametry, jako je -ansi nebo -std=c99 pro určitou konkrétní verzi jazyka.

Druhá chyba: když máš funkci typu int, tak se očekává že bude vracet hodnotu int. Pokud nemá mít žádnou návratovou hodnotu, musíš zadat její typ void, tak jak je to v té ukázce výše.
Když tam necháš int a cokoliv vrátíš, tak je už jedno jestli si to funkce co jí volala vyzvedne nebo ne:

Kód: Vybrat vše

int jednicka(void)
    {
    return 1;
    }

int main(void)
    {
    x=jednicka(); /* zavoláš funkci a dostaneš číslo 1 */
    jednicka();   /* zavoláš funkci a vrácené číslo 1 se vytratí,
                     obvykle zůstane v registru kde ho přepíše další činnost */
    return 0;
    }


Třetí chyba: když už jednou máš proměnnou int* promenna která znamená ukazatel na int, tak jí musíš dál předávat zase jako ukazatel, a ne ukazatel na ukazatel (a potom ukazatel na ukazatel na ukazatel...).
Takže, když jsem vyházel všechno nadbytečné, ta volání v programu musí být napsaná takhle:

Kód: Vybrat vše

int HIGH = 1;
int LOW  = 5000;

void Rising_one(int *HIGH, int *LOW);
void Rising_two(int *HIGH, int *LOW);

void main(void)
{
   for(;;)
    {
      Rising_one(&HIGH, &LOW); /* tady předáváš ukazatele na proměnné */
    }
}

void Rising_one(int *HIGH, int *LOW) /* tady do proměnných dostaneš hodnoty ukazatelů */
{
   if(*HIGH < 4999) /* tady pracuješ na adrese paměti udané ukazatelem */
   {
      ++*HIGH;
      --*LOW;
   }
   
   else
   
      Rising_two(HIGH, LOW); /* tady předáváš hodnoty ukazatelů */

}

void Rising_two(int *HIGH, int *LOW) /* tady zase dostaneš hodnoty ukazatelů */
{
      if(*HIGH > 2)
      {
      --*HIGH;
      ++*LOW;
      }
     else

          Rising_one(HIGH, LOW);
}
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

Uživatelský avatar
Zeppelin
Level 3.5
Level 3.5
Příspěvky: 939
Registrován: říjen 07
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod Zeppelin » 05 črc 2011 16:31

Ale u té druhé funkce se se s HIGH a LOW nic neděje.... mělo by to dělat to co ta první funkce s tím že první funkci dám

HIGH = 1;
LOW = 5000;

A HIGH se inkrementuje a LOW dekremntuje

A druhé funkci dám

HIGH = 4999;
LOW = 1;

Tady v druhé funkci by se mělo HIGH dekremnetovat a LOW inkrementovat ale to se neděje
Intel Celeron G1840, 4GB RAM DDR3, MB Gigabyte H81-S2V, Asus GT610 1GB, SSD Kingston HyperX Fury 120GB, WD 500GB SATAII, Asus DVD-RW LightScribe, Fortron 350W

Jak označit téma za vyřešené
HiJackThis
Návod na údržbu systému pro začátečníky

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod faraon » 05 črc 2011 16:47

Druhé funkci nic nedáš, protože její volání máš za else!

Můžeš to else odstranit nebo si ho tam nechat na příště takhle:

Kód: Vybrat vše

void Rising_one(int *HIGH, int *LOW)
{
   if(*HIGH < 4999)
   {
      ++*HIGH;
      --*LOW;
   }
   else
   {
   }
   Rising_two(HIGH, LOW);
}


Ale to není dobrý nápad, protože během pár okamžiků neukončenou rekurzí naplníš celý zásobník a program spadne. A pokud bys to spustil na nějakém stroji bez ochrany paměti, tak ti to ještě navíc jako bonus přepíše veškerá data i programy v paměti návratovými adresami.
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

Uživatelský avatar
Zeppelin
Level 3.5
Level 3.5
Příspěvky: 939
Registrován: říjen 07
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod Zeppelin » 05 črc 2011 21:31

Bez else nefunguje správně ani ta první.... proč to nemůže být za else? vždyť chci tu druhou funkci zavolat až když proběhne dočtení "HIGH" do 4999.

--- Doplnění předchozího příspěvku (1) ---

Tak jsem to udělal takhle a funguje to. Děkuji moc! A ještě: proč jsou ty funkce void a ne int?

Kód: Vybrat vše

void Rising_one(int *HIGH, int *LOW)
{
   do
   {
      BLUE_OFF;
      GREEN_ON;
      DelayUs(*LOW);
      BLUE_ON;
      GREEN_OFF;
      DelayUs(*HIGH);
      ++*HIGH;
      --*LOW;
   }
   while(*HIGH < 4999);
   
        Rising_two(HIGH, LOW);
}

void Rising_two(int *HIGH, int *LOW)
{
      do
      {
        GREEN_OFF;
        RED_OFF;
        BLUE_ON;
       DelayUs(*LOW);
        GREEN_OFF;
       RED_ON;
       BLUE_OFF;
       DelayUs(*HIGH);
       --*HIGH;
       ++*LOW;
      }
     
      while(*HIGH > 1);
     
           Rising_one(HIGH, LOW);
}


--- Doplnění předchozího příspěvku (1) ---

Tak ještě něco: doplnil jsem třetí poslední funkci ale ta na konci nezavolá první ale běží pořád funkce 1-2-3-2-3-2-3...... to znamená že první jen na začátku a pak už ne. Proč?

Kód: Vybrat vše

void Rising_one(int *HIGH, int *LOW);
void Rising_two(int *HIGH, int *LOW);
void Rising_three(int *HIGH, int *LOW);

int HIGH = 1;
int LOW  = 5000;

void main(void)
{
   for(;;)
    {
       Rising_one(&HIGH, &LOW);
    }
}

void Rising_one(int *HIGH, int *LOW)
{
   do
   {
      BLUE_OFF;
      GREEN_ON;
      DelayUs(*LOW);
      BLUE_ON;
      GREEN_OFF;
      DelayUs(*HIGH);
      ++*HIGH;
      --*LOW;
   }
   while(*HIGH < 4999);
   
        Rising_two(HIGH, LOW);
}

void Rising_two(int *HIGH, int *LOW)
{
      do
      {
        GREEN_OFF;
        BLUE_OFF;
        RED_ON;
       DelayUs(*LOW);
        GREEN_OFF;
       BLUE_ON;
       RED_OFF;
       DelayUs(*HIGH);
       --*HIGH;
       ++*LOW;
      }
     
      while(*HIGH > 1);
     
           Rising_three(HIGH, LOW);
}

void Rising_three(int *HIGH, int *LOW)
{
      do
      {
        BLUE_OFF;
        GREEN_OFF;
        RED_ON;
       DelayUs(*LOW);
        BLUE_OFF;
       GREEN_ON;
       RED_OFF;
       DelayUs(*HIGH);
       ++*HIGH;
       --*LOW;
      }
     
      while(*HIGH < 4999);
     
            Rising_one(HIGH, LOW);
}


--- Doplnění předchozího příspěvku (1) ---

Aha, už to vidím... to byla moje chyba.... předal jsem první funkci "naplněné" proměnné a proto se jakoby první funkce přeskočila. Teď už je to dobré.
Intel Celeron G1840, 4GB RAM DDR3, MB Gigabyte H81-S2V, Asus GT610 1GB, SSD Kingston HyperX Fury 120GB, WD 500GB SATAII, Asus DVD-RW LightScribe, Fortron 350W

Jak označit téma za vyřešené
HiJackThis
Návod na údržbu systému pro začátečníky

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Znovu volání funkce s argumentem

Příspěvekod faraon » 06 črc 2011 08:34

V původním K&R Céčku se nemusel zadávat návratový typ funkce, pokud tam nebylo nic, předpokládal se automaticky int. A naopak, když se do funkce nezadávaly žádné parametry, nebylo potřeba deklarovat vstupní typ/y:

Kód: Vybrat vše

main ()
     {
     return 0;
     }


Jenže kvůli tomu vznikla spousta zbytečných chyb, které napáchaly hromadu škody. C na rozdíl od Pascalu nehlídá za běhu vůbec nic, takže se může stát cokoliv. Proto vznikla norma ANSI C, která nařizuje povinné typování. Překladače sice starší programy přeloží, ale je to kvůli zpětné kompatibilitě, v nových se původní způsob nemá používat. Proto je potřeba zadat jak návratový typ, tak typy všeho co do funkce vstupuje, a pokud něco z toho neexistuje, musí se zadat "prázdný" typ void:

Kód: Vybrat vše

int main(void)
    {
    return 0;
    }


Rozdílů bylo více, například deklarace vstupních proměnných nebo používání složených operátorů, ale postupně (jazyk C vznikl už před čtyřiceti lety, takže má za sebou dost dlouhý vývoj) byly potenciálně nebezpečné nebo nejednoznačné konstrukce z jazyka odstraněny a dnes je při správném použití C dost bezpečný jazyk. Ale jen při správném použití, což obnáší například kontrolování veškerých návratových hodnot! :bomb:

Takže nejdřív ukázka funkce které se předávají dvě hodnoty, a vrací jejich součet:

Kód: Vybrat vše

int sum(int a,int b)
    {
    return a+b;
    }


Podobná funkce, která sice hodnotu vrací, ale nic jí není potřeba dávat, jednoduchý generátor náhodných čísel s automatickým nastavením počáteční hodnoty při prvním spuštění:

Kód: Vybrat vše

int random(void)
    {
    static int seed=0;
    if (!seed)
       seed=time(NULL);
    seed=seed*12345+6789;
    return seed;
    }


Základ je ten, že když máš funkci vracející třeba hodnotu typu int (a samozřejmě jakéhokoliv jiného), musíš jí mít ukončenou příkazem return hodnota; A to ty jsi neměl. Jediný případ kdy se z funkce nevrací příkazem return je právě ten, kdy zadáš návratovou hodnotu void, tedy prázdno.

A nakonec funkce která nic nevrací, zato mění obsah "propůjčených" proměnných, prohodí je navzájem:

Kód: Vybrat vše

void swap(int* a,int* b)
     {
     int w;
     w=*a;
     *a=*b;
     *b=w;
     }
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)


Zpět na “Programování a tvorba webu”

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 3 hosti