Diskuze: Parametry v C - doporučte prosím z čeho se učit
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.
DarkCoder:13.1.2018 18:01
Funkce jsou kostrou programu v jazyce C. Zdrojů, odkud čerpat znalosti, bude jistě hodně. S parametry souvisí mnoho pojmů. To nejdůležitější je vědět co hledat a vědět co je:
obecný formát funkce, argument funkce, prototyp funkce, deklarace, formální parametr, skutečný parametr, procedura, parametrizovaná funkce, void, návratová hodnota, volání funkce, funkce s proměnným počtem parametrů, předběžná deklarace, volání hodnotou, volání odkazem, a další...
To nejpodstatnější je, zda-li se má obsah proměnné měnit či nikoli.
Co konkrétně potřebuješ pochopit?
Učebnice jazyka C od Pavla Herouta je asi najlepšia učebnica. Nájdeš ju ľahko aj ako pdf.
Ahoj, díky oběma.
Mám udělanou kalkulačku a mám tam použít i parametry, tzn. že jí pustím
z konzole a zadám tam třeba "/f 10".
f by byl třeba faktoriál, takže faktoriál čísla 10.
Teď jí mám udělanou obyčejně, že zadám v menu třeba číslo 9 pro
faktoriál a pak zadám číslo, třeba 10.
Kód mám na 1530 řádků, ale dát ho sem klidně můžu, pokud byste ho
chtěli vidět.
Je teda hodně neupravenej a není psanej hezky, spíš jen aby to splňovalo
podmínku 1500ti řádků (taky k té zkoušce). Zkrátit bych ho mohl, ale to
teď zatím ne.
Jediný co zatím mám, že v Mainu je "int argc, char** argv". Zkusím se v tom teď navečer ještě trochu pohrabat, spíš mám strach abych to nemusel celý nějak předělávat, když jsem s tím nepočítal hnedka od začátku.
Ty parametry by stačili třeba na pár funkcí, kdyby to bylo časově složitý na předělání, spíš abych to chápal a pak uměl vysvětlit. Mám tam 60 casů.
Vypadá to nějak takto.
int main(int argc, char** argv)
{
.........
case 9: // faktorial
printf("Zadej cislo: ");
scanf("%ld", &prvnicislofaktorial);
if (prvnicislofaktorial < 0)
{
printf("Faktorial nelze pro zaporne cislo spocitat\n");
return 0;
}
else
{
for (int i = 1; i <= prvnicislofaktorial; ++i)
{
faktorial *= i; // faktorial = faktorial * i;
}
printf("Faktorial cisla %ld je %llu\n", prvnicislofaktorial, faktorial);
}
printf("Prejes si zapsat vysledek do souboru? Y pro ANO / N pro NE\n");
fseek(stdin, 0L, SEEK_END);
zapis = getchar();
if ((zapis == 'Y') || (zapis == 'y'))
{
printf("Zapisuji...\n");
fprintf(soubor, "Faktorial cisla %ld je %llu\n", prvnicislofaktorial, faktorial);
}
break;
}
Potřeboval bych mu pak říct přes tu konzoli, aby udělal ten faktoriál. Mám tu stažený nějaký program, kde už to je, ale nejsem schopnej si to ani vyvodit .
DarkCoder:13.1.2018 21:07
Pokud chceš využívat možnosti načtení argumentů z příkazového řádku, pak funkce main() má tvar:
int main(int argc, char *argv[]){
//...
return 0;
}
To ale není to co bys měl v programu hlavně udělat.
Způsob, jakým volit operaci, měnit nemusíš. Ten je v pořádku.
Ale jednotlivé operace by bylo dobré mít v podobě funkcí.
Tak například pro faktoriál by prototyp funkce mohl vypadat následovně:
long factorial(int n);
Takže by to mělo vypadat nějak takto?
lcase 9: // faktorial
long factorial(int n);
printf("Zadej cislo: ");
scanf("%ld", &prvnicislofaktorial);
if (prvnicislofaktorial < 0)
{
printf("Faktorial nelze pro zaporne cislo spocitat\n");
return 0;
}
else
{
for (int i = 1; i <= prvnicislofaktorial; ++i)
{
faktorial *= i; // faktorial = faktorial * i;
}
printf("Faktorial cisla %ld je %llu\n", prvnicislofaktorial, faktorial);
}
printf("Prejes si zapsat vysledek do souboru? Y pro ANO / N pro NE\n");
fseek(stdin, 0L, SEEK_END);
zapis = getchar();
if ((zapis == 'Y') || (zapis == 'y'))
{
printf("Zapisuji...\n");
fprintf(soubor, "Faktorial cisla %ld je %llu\n", prvnicislofaktorial, faktorial);
}
break;
DarkCoder:13.1.2018 21:30
Chybí Ti tam inicializace proměnné faktoriál na hodnotu 1.
Funkce na faktoriál by pak mohla vypadat třeba takto:
long factorial(int n){
int i;
long result = 1L;
if (n<0) return 0L;
for (i = 1; i <= n; i++) result *= i;
return result;
}
Podotýkám, že funkce není ošetřena zprava a může dojít k přesahu typu long.
Když to udělám stejně jako to máš ty, tak mi to vždycky podtrhne ten long
case 9: // faktorial
long factorial(int n)
{
printf("Zadej cislo: ");
scanf("%ld", &prvnicislofaktorial);
if (prvnicislofaktorial < 0)
{
printf("Faktorial nelze pro zaporne cislo spocitat\n");
return 0;
}
else
{
for (int i = 1; i <= prvnicislofaktorial; ++i)
{
faktorial *= i; // faktorial = faktorial * i;
}
printf("Faktorial cisla %ld je %llu\n", prvnicislofaktorial, faktorial);
}
printf("Prejes si zapsat vysledek do souboru? Y pro ANO / N pro NE\n");
fseek(stdin, 0L, SEEK_END);
zapis = getchar();
if ((zapis == 'Y') || (zapis == 'y'))
{
printf("Zapisuji...\n");
fprintf(soubor, "Faktorial cisla %ld je %llu\n", prvnicislofaktorial, faktorial);
}
}
break;
DarkCoder:13.1.2018 21:39
Prototypy funkcí je dobré uvádět na začátku programu po vložení
hlavičkových souborů. Nebo ještě lépe v samostatném modulu (.h). Pokud
už děláš takto komplexní program, bylo by to elegantnější řešení.
Ale pokud to uděláš následovně:
/* hlavickove soubory */
/* prototypy funkci */
int main(int argc, char * argv[]){
//...
}
/* definice funkci */
Tak to bude obstojné a v pořádku.
DarkCoder:13.1.2018 21:57
Podívej na následující kód, je v něm pouze výpočet a výpis hodnoty faktoriálu bez omáčky:
#define _CRT_SECURE_NO_WARNINGS
// headers
#include <stdio.h>
// prototyps
long factorial(int n);
int main(int argc, char *argv[]) {
long factout;
int factin;
printf("Zadej cislo: ");
scanf("%d", &factin);
factout = factorial(factin);
printf("Faktorial cisla %d = %ld\n", factin, factout);
return 0;
}
// factorial fce
long factorial(int n) {
int i;
long result = 1L;
if (n<0) return 0L;
for (i = 1; i <= n; i++) result *= i;
return result;
}
Jirka:13.1.2018 22:23
Děkuju. A jak ho prosím spustím s těmi parametry přes konzoli? Dostat se k programu pomocí příkazu cd umím, spustit taky, ale máme to spouštět ještě přímo z té řádky, např tedy zadat -faktorial 10. Zkoušel jsem to teď pár kombinacemi a nedaří se mi to.
DarkCoder:13.1.2018 23:19
Za předpokladu, že aplikace se jmenuje fact.exe, bys program z příkazové řádky pak spouštěl následovně:
fact.exe -faktorial <hodnota> tedy např. fact.exe -faktorial 10
a kód bys upravil následovně:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
long factout;
if ((argc != 3) || (strcmp(argv[1],"-faktorial"))) exit(1);
factout = factorial(atoi(argv[2]));
printf("Faktorial cisla %d = %ld\n", atoi(argv[2]), factout);
return 0;
}
+20 Zkušeností
+2,50 Kč
Ahoj, děkuju moc. Našel jsem si k tomu vysvětlivky a mám pocit že to i
chápu a v mém programu mi to taky funguje, tak snad to budu chápat i u
zkoušky Ještě jednou
díky!
Kdyžtak bych to tu ještě v případě potřeby trochu zaspamoval, ale snad si
s tím co tu je vystačím.
Ahoj,
tak jsem ještě narazil.. nevíš prosím kde by mohla být chyba? Pokouším
se to samé udělat pro součet čísel.
Toto mám nahoře:
if ((argc != 4) || (strcmp(argv[1], "-soucet"))) // argc predstavuje pocet argumentu prikazove radky, zde musi byt tedy 3
{
exit(1); // indicates unsuccessful termination
}
vysledeksouctu = factorial(atoi(argv[2]) & (atoi(argv[3]))); // argv[2] ukazuje na treti retezec, tedy cislo
//vysledeksouctu = factorial(atoi(argv[3]));
printf("Soucet cisel je %ld\n", vysledeksouctu); // The C library function int atoi converts the string argument to an integer (type int)
return 0;
Toto dole:
float soucetcisel(int a, int b)
{
float vysledeksouctucisel;
if ((a < 0) || (b < 0))
{
return 0;
}
else
{
vysledeksouctucisel = a + b;
}
}
Když zadám parametry, tedy "test -soucet 5 2", tak mi to nic nevypíše a
hodí mě to o krok zpět.
Zkoušel jsem s tím trochu čachrovat ale nic jsem nevymyslel .
Dělám to stejně jako ty, ale někde asi dělám pořád chybu.
ostrozan:14.1.2018 14:26
Chybí ti tam jedna podstatná informace, která se ho dost týká :
Deklarace prototypu funkce, natož její definice není možná v těle jiné
funkce - což evidentně udělal a proto mu to házelo chybu
DarkCoder:14.1.2018 15:17
Pokud sloučím oba dva své příspěvky (čas 21.57 a čas 23.19) do jednoho, vypadá výsledný kód takto:
// faktorial z prikazove radky
#define _CRT_SECURE_NO_WARNINGS
// headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// prototyps
long factorial(int n);
int main(int argc, char *argv[]) {
long factout;
if ((argc != 3) || (strcmp(argv[1], "-faktorial"))) exit(1);
factout = factorial(atoi(argv[2]));
printf("Faktorial cisla %d = %ld\n", atoi(argv[2]), factout);
return 0;
}
// factorial fce
long factorial(int n) {
int i;
long result = 1L;
if (n<0) return 0L;
for (i = 1; i <= n; i++) result *= i;
return result;
}
Jo, jo, já to tak mám a funguje mi to perfektně . Akorát mi to nefunguje, když
jsem se to pokoušel dělat pro součet dvou čísel viz příspěvek ve
13:38.
Snažil jsem se to z toho odvodit ale nevidím v tom chybu
Když zadám ten parametr pro součet tak to neudělá nic.
DarkCoder:14.1.2018 15:35
Z příspěvku který poslal není žádný náznak toho, že by provedl deklaraci či definici funkce v těle jiné funkce. Ve zkratce shrnu, že to co provedl bylo chybné volání funkce, nikoli definice ani deklarace. Chyb je tam více, ale o tom se rozepíši v samostatném příspěvku.
DarkCoder:14.1.2018 15:52
Takto to máš samostatně pro součet:
// soucet z prikazove radky
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// prototyp fce soucet - deklarace funkce
int soucet(int m, int n);
int main(int argc, char *argv[]) {
if ((argc != 4) || (strcmp(argv[1], "-soucet"))) exit(1);
// Jako argument funkce printf je pouzito volani fce soucet
printf("Soucet cisel %d a %d = %d\n", atoi(argv[2]), atoi(argv[3]), soucet(atoi(argv[2]), atoi(argv[3])));
return 0;
}
// fce soucet - definice funkce
int soucet(int m, int n) {
return m + n;
}
Tak mi to furt nejde. Vypadá to nějak takto:
long factorial(int n);
int soucet(int m, int n);
int main(int argc, char** argv[]) {
Tady je hromada promennych atd...
// faktorial
if ((argc != 3) || (strcmp(argv[1], "-faktorial"))) // argc predstavuje pocet argumentu prikazove radky, zde musi byt tedy 3
{
exit(1); // indicates unsuccessful termination
}
vysledekfaktorial = factorial(atoi(argv[2])); // argv[2] ukazuje na treti retezec, tedy cislo
printf("Faktorial cisla %d = %ld\n", atoi(argv[2]), vysledekfaktorial); // The C library function int atoi converts the string argument to an integer (type int)
return 0;
// soucet cisel
if ((argc != 4) || (strcmp(argv[1], "-soucet"))) exit(1);
// Jako argument funkce printf je pouzito volani fce soucet
printf("Soucet cisel %d a %d = %d\n", atoi(argv[2]), atoi(argv[3]), soucet(atoi(argv[2]), atoi(argv[3])));
return 0;
} // konec main
// faktorial funkce
long factorial(int n)
{
int i;
long result = 1;
if (n < 0)
{
return 0;
}
for (i = 1; i <= n; i++)
{
result *= i;
}
return result;
}
// soucet funkce
int soucet(int m, int n)
{
return m + n;
}
Faktoriál mi to provede, ale ten součet stále ne.
Do konzole píšu "test -soucet 2 3".
DarkCoder:14.1.2018 17:04
Ahoj, tak jsem ještě narazil.. nevíš prosím kde by mohla být chyba? Pokouším se to samé udělat pro součet čísel.
Jak by to mohlo vypadat pro součet čísel jsem již uvedl v předchozím
příspěvku.
Teď bych se chtěl hlavně vyjádřit k chybám a k tomu proč se Ti to
nepodařilo zprovoznit.
Než používat pojmy "dole" a "nahoře" je lepší používat pojmy uvnitř
funkce a vně funkce.
Dále pro práci s funkcemi potřebuješ znát následující pojmy - prototyp
funkce, deklarace funkce, definice funkce a volání funkce.
Začnu samotnou definicí funkce. To jakého typu bude její návratová hodnota a parametry, je jen na tobě. To hlavní, co by tato funkce měla mít a co ti tam chybělo a již to zmínil ostrozan, je její návratová hodnota. Tu tam sice máš ale ne pro výsledek ale pro omezení platnosti funkce. Navíc sčítat můžeme i záporná čísla a tak je tato podmínka nesprávná. Else navíc není potřeba, pokud jej v tomto případě neuvedeš bude kód efektivnější (bude se zpracovávat méně instrukcí).
Prototyp je deklarací funkce a je důležitý. Informuje program o správném použití funkce (Dříve než je funkce použita zná informace o počtu a typy parametrů a tedy nesrovnalost ve volání funkce může být odchycena).
Navrácení hodnoty můžeš udělat dvěma způsoby. S tím souvisí kromě návratové hodnoty znalost pojmů: volání hodnotou, volání odkazem a formální parametr, skutečný parametr.
První způsob za pomocí return kde prototyp funkce vypadá takto:
int soucet(int m, int n);
Výsledek funkce pak můžeš přiřadit nějaké proměnné za pomoci
volání funkce (viz. ukázky kódů výše).
m a n jsou formální parametry funkce a používá se zde volání hodnotou.
Návratová hodnota se získává použitím příkazu return.
Druhý způsob za pomoci volání odkazem kde prototyp funkce vypadá takto:
void soucet(int m, int n, int *vysl);
Zde výsledek funkce přímo přiřazuješ nějaké proměnné jejíž adresa je uvedena jako skutečný parametr funkce při volání funkce. Zde se používá volání odkazem. V tomto případě se už nepoužívá návratová hodnota funkce proto je použit datový typ void. Volání funkce pak vypadá následovně:
soucet(5, 10, &x);
Kde do proměnné x se uloží výsledek součtu hodnot 5 a 10.
V sekci ve volání funkce mícháš dvě funkce které spolu nesouvisí (faktoriál a součet). Faktoriál tam být vůbec nemá. Používáš bitový součin & který v příkladu vůbec nepotřebuješ. Pokud chci do proměnné přiřadit výsledek součtu argumentů zadaných z příkazové řádky pak bych použil toto:
vysledek = soucet(atoi(argv[2]), atoi(argv[3]));
Typ proměnné výsledek je důležitý a měl by korespondovat s návratovým typem funkce soucet()! Pokud by tomu tak nebylo, dochází k implicitné konverzi typu pravé strany na typ levé strany, což může v některých případech vést k chybě programu (některé konverze jsou nepovolené). V lepším případě dostaneš nesmyslnou hodnotu. V nejlepším případě dosáhneš správného výsledku, ale způsob, jakým toho bylo dosaženo je nesprávný. Nakonec při volání funkce znát typ návratové hodnoty a tedy použít správný specifikátor formátu ve funkci printf() (%ld pro long, %d pro int, %f pro float a double, atd).
DarkCoder:14.1.2018 17:38
Chybně definuješ funkci main(), ve druhém parametru máš hvězdičku navíc. Správně je:
int main(int argc, char *argv[])
Pokud zadáváš argumenty na příkazové řádce, musíš znát povolené
kombinace programem.
Tvé současné povolené kombinace programem jsou:
test.exe -faktorial <hodnota> tedy např. test.exe -faktorial 10
test.exe -soucet <hodnota> <hodnota> tedy např. test.exe -soucet 2
3
v prvním případě může funkce přijmout 3 argumenty, ve druhém 4.
Podívej co se stane, když budu chtít provést operaci součet a zadám: test.exe -soucet 2 3
Podmínka:
if ((argc != 3) || (strcmp(argv[1], "-faktorial"))) exit(1);
Způsobí ukončení programu protože zadáváš 4 argumenty kdežto program testuje na 3.
Výraz:
(argc != 3)
je vyhodnocen jako pravdivý (4!=3) a automaticky ukončuje (exit). Zbylé výrazy v podmínce už ho ani nezajímají.
kód musíš upravit tak, aby program dokázal zpracovat operace na základě hodnoty druhého argumentu a odlišného počtu argumentů.
Ještě jedna věc, je dobré nemíchat způsoby výpisu výsledku operace. Způsob jaký jsem uvedl u operace součet byl ukázán pro zajímavost, že není třeba vůbec definovat proměnnou. Doporučuji druhý způsob (u operace součet). Důvodem je že každá funkce vrací odlišný typ, ušetříš paměť za defici proměnných.
Ahoj, děkuju za vyčerpávající odpovědi, pokusím se to upravit jak říkáš. Nevíš prosím jak to tedy udělat, aby mi nekolivdovaly ty argumenty, viz
//faktorial
if ((argc != 3) || (strcmp(argv[1], "-faktorial"))) // argc predstavuje pocet argumentu prikazove radky, zde musi byt tedy 3
{
exit(1); // indicates unsuccessful termination
}
vysledekfaktorial = factorial(atoi(argv[2])); // argv[2] ukazuje na treti retezec, tedy cislo
printf("Faktorial cisla %d = %ld\n", atoi(argv[2]), vysledekfaktorial); // The C library function int atoi converts the string argument to an integer (type int)
return 0;
// soucet cisel
if ((argc != 4) || (strcmp(argv[1], "-soucet"))) exit(1);
// Jako argument funkce printf je pouzito volani fce soucet
printf("Soucet cisel %d a %d = %d\n", atoi(argv[2]), atoi(argv[3]), soucet(atoi(argv[2]), atoi(argv[3])));
return 0;
Když jsem faktoriál zakomentoval, tak se mi součet provede, jen nevím,
jak to oddělit .
Pokouším se to porovnávat zda argv = "-faktorial" nebo "-soucet", ale
vždycky mi to spadne.
DarkCoder:14.1.2018 18:29
Pokud máš na výběr z více variant, nesmíš ukončit program dřív než projdeš všechny kombinace. Použití funkce exit() je v tomto případě nesprávné. Test podmínek musíš v tomto případě obrátit. Níže přikládám kód:
// soucet a faktorial z prikazove radky
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long factorial(int n);
int soucet(int m, int n);
int main(int argc, char *argv[]) {
if ((argc == 3) && (!strcmp(argv[1], "-faktorial"))) printf("Faktorial cisla %d = %ld\n", atoi(argv[2]), factorial(atoi(argv[2])));
else if((argc == 4) && (!strcmp(argv[1], "-soucet"))) printf("Soucet cisel %d a %d = %d\n", atoi(argv[2]), atoi(argv[3]), soucet(atoi(argv[2]), atoi(argv[3])));
return 0;
}
long factorial(int n) {
int i;
long result = 1L;
if (n<0) return 0L;
for (i = 1; i <= n; i++) result *= i;
return result;
}
int soucet(int m, int n) {
return m + n;
}
ostrozan:14.1.2018 18:31
V tom případě se podívej ještě jednou a lépe
Hned na prvním řádku máš
case 9: // faktorial
Co bys řekl, že to je?
Já myslím, že část switche, který pravděpodobně nevisí v luftě, ale je
v těle funkce - dokonce funkce main, jak je vidět v příspěvku o něco
výše (20:39)
Ale na druhou stranu - tyhle manýry začátečníků, kteří si nevím z
jakého důvodu myslí, že když přehodí útržky kódu bez jakýchkoliv
souvislostí, tak případným lidem ochotným pomoct "zjednoduší" práci taky
nemám moc rád.
DarkCoder:14.1.2018 18:48
Ano, tam se jednalo o deklaraci funkce na nesprávném místě. To však už bylo řešeno ve dvou následujících příspěvcích (21.39 a 21.57). To se týkalo ještě způsobu provádění operace přímo v programu. Další části se již týkaly řešení načtení z příkazové řádky. Tvůj příspěvek o chybějícím příkazu return se jistě vztahuje k příspěvku v čase 13.38 začínající:
Ahoj, tak jsem ještě narazil.. nevíš prosím kde by mohla být chyba? Pokouším se to samé udělat pro součet čísel.
A tady opravdu žádná deklarace ani definice funkce v jiné funkci není.
Zobrazeno 31 zpráv z 31.