Stránka 1 z 3

[C]Detekce konstanty

Napsal: 20 bře 2014 14:27
od CZechBoY
Zdar,
jde nějak v C detekovat jestli je proměnná konstanta nebo dynamicky alokovaná?
Mm trošku problém s odalokováním paměti :-/ Když odalokuju konstantu tak to hodí seg fault.
Někdy je proměnná dynamicky alokovaná a někdy má přiřazenou hodnotu z konstanty - defaultní hodnota programu.

Děk za tipy.

Re: [C]Detekce konstanty

Napsal: 20 bře 2014 15:10
od MiliNess
Asi nemyslíš konstantu, ale automatickou proměnnou na zásobníku, případně statickou proměnnou vs. dynamicky alokovanou proměnnou, ne?
Pokud to potřebuješ zjišťovat, tak to píšeš blbě.
Můžeš sem hodit nějaký konkrétní příklad?

Re: [C]Detekce konstanty

Napsal: 20 bře 2014 16:00
od CZechBoY
Konkrétní případ je, že mám aplikaci, která si dává vlastní výchozí hodnoty proměnným, když nejsou zadány přes argument.
Třeba dám projekt.exe -parametr1 -parametr3 tzn když není parametr2 tak si tam dám nějakou hodnotu výchozí.
Jelikož nevim dopředu délku těch parametrů tak si je dynamicky alokuju. K čemu ale dynamicky alokovat místo pro konstantní řetězec, u kterýho vim délku, tedy potřebný počet bajtů v paměti?

Zatím jsem to udělal tak, že alokuju dynamicky i ty konstanty, aby mi to neházelo seg fault u uvolnění paměti.

Re: [C]Detekce konstanty

Napsal: 20 bře 2014 16:52
od faraon
A jak ty parametry načítáš? Když máš tohle:

Kód: Vybrat vše

int main(int argc, char *argv[])

tak dostaneš počet položek a pole řetězců, kde je v [0] název programu a pak případné argumenty jak jdou za sebou. Ty bys po příkazu

Kód: Vybrat vše

projekt.exe -parametr1 -parametr3

měl takový stav:
argc=2
argv[0]="projekt.exe"
argv[1]="-parametr1"
argv[2]="-parametr3"

O délku se starat nemusíš, a o uvolnění také ne, to se udělá automaticky při ukončení programu.

Mimochodem, také jsem viděl tenhle tvar:

Kód: Vybrat vše

int main(int argc, const char *argv[])

Re: [C]Detekce konstanty

Napsal: 20 bře 2014 16:54
od CZechBoY
Na novej tvar to já kašlu, připadá mi to stejný.
Nezajmá mě co je v parametrech, to je pro ilustraci, abyste pochopili můj problém... tzn. dosazení výchozí hodnoty když parametr chybí.

Re: [C]Detekce konstanty

Napsal: 20 bře 2014 18:11
od MiliNess
Já to ale nechápu. V Céčku už pár let programuju, nikdy jsem ale nepotřeboval řešit to, co ty.
Musel bys funkci free() umístit do bloku __try, v handleru __except pak vyjímku zachytit a vyřešit.
To platí pro Windows, pro Linux je to trochu jinak.

Re: [C]Detekce konstanty

Napsal: 21 bře 2014 05:29
od faraon
To není nový tvar, ale docela šikovná věc. Tím modifikátorem const totiž překladači něco sděluješ...

Pořád mi ale není jasné co máš za problém. Program prostě dostane seznam argumentů a ty si musí sám rozebrat. Při tom, pokud nějaký očekávaný není na seznamu, dosadí defaultní hodnotu. Ten seznam také může být prázdný, pak ji dosadí do všech.

Asi bude lepší sem pro ilustraci hodit nějaký jednoduchý prográmek, aby bylo jasné co přesně děláš.

Re: [C]Detekce konstanty

Napsal: 21 bře 2014 10:05
od CZechBoY
Jáj, pořád nevim co nechápete :D
Ukázku zkusim teda no ... :idea:

Kód: Vybrat vše

#define DEFAULT_CHAR1 "nazdar"
#define DEFAULT_CHAR2 "cojee"

// parsuje parametry...
int parseParams(char** args) {
  struktura params {char1; char2; char3};

  if (args[1] == "-char2") {
    params.char1 = DEFAULT_CHAR1;
    params.char2 = DEFAULT_CHAR2;
  } else {
    params.char1 = (char*)malloc(strlen(args[2]));
    if (params.char1 == NULL) {epic fail}
    strcpy(params.char1, args[2]);
  }
}


Třeba takhle, akorát neberu hodnoty přímo z args, ale ještě rozřežu ten arg na více částí a potom ty části ukládám do struktury.

Re: [C]Detekce konstanty

Napsal: 21 bře 2014 11:19
od MiliNess
Takový problém musíš řešit proto, že ta konstrukce není moc šťastná.
Prostě buď použij strukturu

Kód: Vybrat vše

struct params
   {
      char * char1;
      char * char2;
      char * char3;
   };

a paměť alokuj jak v případě, že budeš používat defaultní paramert, tak v případě, že budeš kopírovat paramert z command line bufferu
nebo použij takovou strukturu

Kód: Vybrat vše

struct params
   {
      char char1[1000];
      char char2[1000];
      char char3[1000];
   };

Nemusíš nic dynamicky alokovat a délka parametru bude těžko více jak 999 znaků. Pro jistotu si délku můžeš ošetřit.
Osobně v takových situacích vůbec paměť dynamicky nealokuji, protože se alokace může posrat. Čím je to jednodušší,
tím méně míst, kde může vzniknout chyba. Navíc můžeš zapomenout uvolnit paměť.

Re: [C]Detekce konstanty

Napsal: 21 bře 2014 20:47
od faraon
Chybička se vloudila, správně to včera mělo být takhle:
argc=3 !!!
argv[0]="projekt.exe"
argv[1]="-parametr1"
argv[2]="-parametr3"


Ano, je to sice k neuvěření, ale v Céčku pole začínají od nuly, a řetězce se opravdu porovnávat pomocí == nedají (tohle není BASIC), takže jsem ten tvůj program trochu (spíš totálně) překopal a zprovoznil:

Kód: Vybrat vše

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

#define DEFAULT_CHAR1 "nazdar"
#define DEFAULT_CHAR2 "cojee"

typedef struct {
               char *char1;
               char *char2;
               char *char3;
               } ARGS;



/* parsuje parametry... */
int parseParams(char **args)
    {
    ARGS params;

    if (!strcmp(args[1],"-char2"))
       {
       params.char1 = DEFAULT_CHAR1;
       params.char2 = DEFAULT_CHAR2;
       printf("Zkopírovány konstanty:\n%s\n%s\n",params.char1,params.char2);
       }
    else
       {
       if ((params.char1 = (char*)malloc(strlen(args[1]))))
          {
          /* process */
          strcpy(params.char1,args[1]);
          printf("Úspěšně naalokováno a zkopírováno:\n%s\n",params.char1);
          free(params.char1);
          }
       else
          {
          /* epic fail */
          fprintf(stderr,"ERROR alokace!\n");
          }
       }

    return 0;
    }



int main(int argc,char *argv[])
    {
    int i;

    /* nejdřív výpis všech argumentů pro kontrolu */
    printf("argc:\t%d\n",argc);
    for (i=0;i<argc;++i)
        {
        printf("%d:\t%s\n",i,argv[i]);
        }

    /* a pokud byly nějaké zadány, zavoláme funkci */
    if (argc>1)
       {
       parseParams(argv);
       }
    else
       {
       fprintf(stderr,"Nemám žádné parametry!\n!");
       }

    return 0;
    }


V té funkci nemůžeš testovat args[2], protože nevíš jestli tam nějaký další je! Musel bys předávat i argc.
Porovnávat řetězce se dá jedině pomocí funkce strcmp(), kopírovat pomocí strcpy().
Strukturu je lepší deklarovat jako vlastní typ, lépe se pak s ní pracuje, bez toho musíš všude psát struct proměnná.

Re: [C]Detekce konstanty

Napsal: 24 bře 2014 00:01
od CZechBoY
Jo, chápu že stringy nemůžou porovnávat přes ==, já íšou většinou v pseudokodu :D
Tisícovej buffer fakt nechci používat, však to žere 1kB paměti ať tam nacpu 2 znaky nebo 1000 ne?

faraon: Takže když dám strcpy tak nemusim alokovat paměť? To je super, ale už jsem projekt odevzdal :D
Jak já se s**l s tim alokováním a nultejma bajtama na konci :roll:

Re: [C]Detekce konstanty

Napsal: 24 bře 2014 05:37
od faraon
Alokovat jí musíš, ale jen tolik kolik je potřeba. A to strcpy() tam zkopíruje i ten nulový znak na konci. Teď mě napadá že to asi mělo být spíš
if ((params.char1 = (char*)malloc(strlen(args[1])+1)))
Tak to dopadá když si člověk neidělá všechno sám :lol:

Na strcpy() bacha, protože to kopíruje až do '\0', pokud ho tam nemáš, jede dokud ho nenajde, což může být docela dlouho... Někdy i do segfaultu!
To se tady nemůže stát, protože ten řetězec už je (měl by být) zkontrolovaný, tak můžeš použít rychlejší funkci.
Pak je také strncpy(), kterému zadáš i kolik bajtů maximálně smí zkopírovat, aby nedošlo k přetečení.

Můj pseudokód by vypadal spíš takhle nějak:
if equal(string1,string2)...

Alokování je fajn věc, akorát se musí vždy kontrolovat návratová hodnota. Ale větší zábava je s uvolňováním, aby ti program nežral paměť jako Firefox ;-)

Ještě mě napadla jedna věc, teoreticky by konstanta měla být uložená v jiném bloku paměti než ta tvoje alokace, takže by stačilo porovnat pár ukazatelů. Ale záleží na druhu a na tom kdy vznikla, navíc není jisté co s tím překladač při optimalizaci a operační systém při spouštění provedou, asi by to nebylo spolehlivé.