Diskuze: Problém s dynamicky alokovaným polem

C++ C a C++ Problém s dynamicky alokovaným polem

Avatar
igimas
Člen
Avatar
igimas:

Ahoj, dělám si program pro čtení wav souborů (vím, že jsou na to už hotové knihovny, ale chci se učit). Problém je, že kód, který následuje po dynamicky alokované proměnné, která je pro vzorky wavu, se nevykoná. I přesto se program tváří, že mu nic nevadí a funguje...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define POCETINFO 128

int najdi(char* vstup, char* neco){
    int poradi, cneco=0;
    int delkavstup;
    int delkaneco;

    delkavstup=POCETINFO;
    delkaneco=strlen(neco)-1;
    for(poradi=0;poradi<delkavstup;poradi++){
        if(vstup[poradi]==neco[cneco]){
            if(cneco==delkaneco)
                return poradi;
            cneco++;
        }
        else{
                cneco=0;
        }

    }
    return 0;
}


int main(int argc, char** argv) {

    short *wavik;
    short *pokus;
    short *pomocny;
    unsigned short d;
    unsigned int pocetvzorku, velikost;
    int pozice;
    int i, kanalu=1, N=16, xcteni;
    char info[POCETINFO]; //vyhrazene misto pro zjisteni infa o souboru
    char nazev[40];
    FILE *fp;

    info[POCETINFO]=NULL;  //osetreni delky retezce


printf("Zadejte nazev wav souboru, kteru chcete otevrit: ");
scanf("%39s", nazev);

 ///////////////////////////////////////// algoritmus cteni wavu

fp=fopen(nazev,"rb"); // open the binary file for reading

fread(&info,POCETINFO-1,1,fp);   //zapis zacatku souboru do info kvuli zjisteni kanalu, Fs apod

//zjisteni poctu kanalu apod
pozice=najdi(info,"fmt"); // Zjistíme pozici znaku fmt v textu
fseek (fp , pozice+8 , SEEK_SET ); // zjisteni poctu kanalu
fread(&kanalu,2,1,fp);   // zapsani poctu do promenne
fseek (fp , pozice+20 , SEEK_SET ); // zjisteni poctu bitu na vzorek
fread(&N,2,1,fp);   // zapsani poctu do promenne

pozice = najdi(info,"data"); // Zjistíme pozici znaku data v textu
fseek (fp , pozice+1 , SEEK_SET ); //nalezeni velikosti vsech vzorku
fread(&velikost,4,1,fp);
pocetvzorku=velikost/(N/8);//deli se jeste 8 protoze se pocita pocet bytu

printf("\n Pocet vzorku je %d\n",pocetvzorku);
printf(" Tj. vzorku na kanal %d\n",pocetvzorku/kanalu);
printf(" Pocet bitu %d\n",N);
printf(" Kanalu %d\n",kanalu);



pomocny=(short*)malloc(sizeof(short)*pocetvzorku); //alokovani mista v promenne pro 1. kanal
wavik=(short*)malloc((sizeof(short)*pocetvzorku)/kanalu); //alokovani mista v promenne pro 1. kanal

fseek (fp,pozice+5,SEEK_SET); //nastaveni cteni na 1.vzorek
fread(&pomocny,pocetvzorku,1,fp);   //ulozeni vsech vzorku do pomocne promenne
fclose(fp);
 for(i=0;i<xcteni;i++)  // precteni vzorku 1.kanalu (nebo mono)
 {

     *wavik=*pomocny;
     wavik++;
     pomocny++;
     printf("%d ",*wavik);
 }


 free(pomocny);
 free(wavik);

    return (EXIT_SUCCESS);

}
 
Odpovědět 22.2.2015 20:05
Avatar
Martin Dráb
Redaktor
Avatar
Martin Dráb:

Tady máš například zápis mimo rozsah pole (pole jsou v Cčku indexována od 0, takže v tvém případě je posledním platným indexem hodnota POCETINFO-1.

char info[POCETINFO];
...
nfo[POCETINFO]=NULL;

Dále nekontroluješ, zda volání různých funkcí, které může selhat, opravdu uspělo nebo ne (fseek, fread, fwrite, malloc). A přitom na jeho úspěchu velmi záleží. Pak se těžko hledá, proč to nefunguje.

Závěrečný for cyklus děláš tolikrát, kolikrát ti diktuje proměnné xcteni, kteroužto ale neinicializuješ.

Počítám, že překldač by měl na takovýto kód vyhodit nějaká varování (není-li špatně nastaven). A řešit varování OPRAVDU MÁ smysl.

Nahoru Odpovědět 22.2.2015 20:55
2 + 2 = 5 for extremely large values of 2
Avatar
David Novák
Tým ITnetwork
Avatar
Odpovídá na igimas
David Novák:

Jak říká Vrtule.. :)

Plus, nastav si následující příznaky překladače:

-Wall -Wextra -Werror -pedantic

Bude tě pak víc hlídat ;)

Nahoru Odpovědět 22.2.2015 21:14
Chyba je mezi klávesnicí a židlí.
Avatar
igimas
Člen
Avatar
igimas:

Díky za odpovědi, posílal jsem sem promazanou verzi, takže určení počtu opakování pole tam sice je, ale sem jsem to nezkopíroval. Příznaky prohlížeče jsem si nastavil až na ten Werror-nedovolil mi překlad když použiju komentář.
Chybu jsem nakonec našel, že při čtení vzorků ze souboru mám adresu proměnné, která už je sama ukazatel, takže stačilo smazat & zde:
fread(&pomocny,po­cetvzorku,1,fp); //ulozeni vsech vzorku do pomocne promenne

Mám už udělaný úspěšně i zápis vzorků do wav souboru. Problém teď mám, jak z toho udělat funkci nebo ještě lépe knihovnu, abych mohl wav soubory editovat. Problém mám aby funkce vrátila alespoň dva vektory(tj. levý a pravý kanál), které jsou navíc dynamicky alokované. Jak toho docílit?

 
Nahoru Odpovědět 24.3.2015 16:48
Avatar
Odpovídá na igimas
Libor Šimo (libcosenior):

Komentar pouzi /* */ a bude to v poriadku.

Nahoru Odpovědět 24.3.2015 16:53
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na igimas
Libor Šimo (libcosenior):

Dynamicky ich alocuj na halde a pouzi pointery na ne ako parametre funkcie. Navratova hodnota bude void, ale parametre budu vstupno-vystupne.

Nahoru Odpovědět 24.3.2015 16:58
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
David Novák
Tým ITnetwork
Avatar
Odpovídá na Libor Šimo (libcosenior)
David Novák:

nebo může třeba vracet strukturu o dvou pointrech.. :D (pokud by trval na tom, že to musí vracet..)

Nahoru Odpovědět  +1 24.3.2015 17:05
Chyba je mezi klávesnicí a židlí.
Avatar
igimas
Člen
Avatar
igimas:

Díky, ale pořád nevím jak to provést. Zkoušel jsem je alokovat v dané funkci a pak vracet ukazatel, ale ani to nefungovalo, navíc potřebuju vrátit 3. A pokud se nebude funkcí nic vracet, tak by to musela být globální proměnná, ne? Můžete mi sem prosím hodit nějaký jednoduchý příklad?

 
Nahoru Odpovědět 26.3.2015 20:12
Avatar
Libor Šimo (libcosenior):

Skús nejak takto:

#include <stdio.h>

void prepocitaj(int *a, int *b, int *c)
{
    *a *= *b;
    *b *= *c;
    *c = *b / *a;
}

int main(void)
{
    int i = 11, j = 22, k = 33;

    prepocitaj(&i, &j, &k);
    printf("%d, %d, %d", i, j, k);

    return 0;
}

alebo

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

void prepocitaj(int *pole)
{
    pole[0] *= pole[1];
    pole[1] *= pole[2];
    pole[2] = pole[1] / pole[0];
}

int main(void)
{
    int *pole;

    if ((pole = (int *) malloc(3 * sizeof(int))) == NULL) {
        printf("Malo pamati!");
        return 1;
    }
    pole[0] = 11;
    pole[1] = 22;
    pole[2] = 33;

    prepocitaj(pole);
    printf("%d, %d, %d", pole[0], pole[1], pole[2]);

    return 0;
}
Nahoru Odpovědět  +1 27.3.2015 7:03
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
igimas
Člen
Avatar
igimas:

Díky, ale já to potřebuju naopak, tj. až ve funkci alokovat pole o délce, kterou zjistím až v této funkci, něco na způsob tohoto(což mi ale taky nefunguje):

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

    int dynam(void){
        int *a;
        int i;
        a=(int*)malloc(sizeof(int)*10);

        for(i=0;i<10;i++){
            a[i]=i+1;
        }
        return a;
    }


int main(int argc, char** argv) {
    int *a;
    int i;
    a=dynam();
    for(i=0;i<10;i++){
        printf("ulozeno na %d. pozici: %d\n",i,*a);
        a++;
    }
    //free(a);
    return (EXIT_SUCCESS);

}
 
Nahoru Odpovědět 31.3.2015 17:12
Avatar
Odpovídá na igimas
Libor Šimo (libcosenior):

int dynam(void){
int a;
int i;
a=(int
)malloc(si­zeof(int)*10);

for(i=0;i<10;i++){
a[i]=i+1;
}
return a;
}

Návratovú hodnotu máš nastavenú na premennú typu in a nie na pointer na premennú typu int.

int * dynam(void){

Nahoru Odpovědět  +1 1.4.2015 7:00
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
David Novák
Tým ITnetwork
Avatar
Odpovídá na igimas
David Novák:

(trochu OT)
zkus používat mezery.. kód je pak výrazně přehlednější a čitelnější.. ;)

for(i = 0; i < 10; i++){
  a[i] = i + 1;
}
Nahoru Odpovědět 1.4.2015 8:45
Chyba je mezi klávesnicí a židlí.
Avatar
Odpovídá na David Novák
Libor Šimo (libcosenior):

Sorry, len som skopíroval jeho kód a zabudol som ho dať do code.

Nahoru Odpovědět 1.4.2015 10:11
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
David Novák
Tým ITnetwork
Avatar
Odpovídá na Libor Šimo (libcosenior)
David Novák:

To nebylo na tebe.. ;)
Jen malá rada pro OP ohledně formátování kódu..

Nahoru Odpovědět 1.4.2015 10:14
Chyba je mezi klávesnicí a židlí.
Avatar
igimas
Člen
Avatar
igimas:

Díky už mi to funguje, ještě teda řeším, že potřebuji vracet dva vektory (levý a pravý kanál wav souboru) a ještě jeden integer, kde bude délka těch vektorů( oba jsou pochopitelně stejně dlouhé). Nedal by se na to nějak použít ukazatel na ukazel? Zatím pořádně nechápu na co ho vůbec použít a jak se používá, ale něco mi říká, že tady by to šlo :-D . Pak mám tedy ještě další problém, který ale alespoň zdánlivě ničemu nevadí(OS si to pak asi uvolní nějak sám) a to je, že mi potom nelze funkcí free uvolnit alokovanou paměť, protože uvolnění musí být až v jiné funkci.

 
Nahoru Odpovědět 5.4.2015 13:16
Avatar
Odpovídá na igimas
Libor Šimo (libcosenior):

Pouzi ten sposob, co som ti pisal, teda pointery na premenne, ktore budu vstupno vystupnym parametrom. Uvolnuje sa alocovane pole, ale to tam mas.

Nahoru Odpovědět 7.4.2015 9:17
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na igimas
Libor Šimo (libcosenior):
#include <stdio.h>
#include <stdlib.h>
/* #include <string.h> */

int **vytvor_viacrozmerne_pole(const int riadky, const int stlpce)
{
        int **p_p_x, i;

        if ((p_p_x = (int **) malloc(riadky * sizeof(int *))) == NULL) {
        printf("Nedostatok pamati.\n");
        exit(1);
    }
        for (i = 0; i < riadky; i++)
                if ((p_p_x[i] = (int *) malloc(stlpce * sizeof(int))) == NULL) {
            printf("Nedostatok pamati.\n");
            exit(1);
        }
        return(p_p_x);
}

void uvolni_viacrozmerne_pole(int **p_p_x, const int riadky)
{
        int i;

        for (i = 0; i < riadky; i++)
                free((void *) p_p_x[i]);
        free((void *) p_p_x);
}

void napln_viacrozmerne_pole(const int riadky, const int stlpce, int **p_p_x)
{
    int i, j;

    for (i = 0; i < riadky; i++) {
        for (j = 0; j < stlpce; j++) {
            p_p_x[i][j] = (i + 1) * (j + 1);
        }
    }
}

int *vytvor_jednorozmerne_pole(const int velkost)
{
    int *p_p;

    if ((p_p = (int *) malloc(velkost * sizeof(int))) == NULL) {
        printf("Nedostatok pamati.\n");
        exit(1);
    }
    return p_p;
}

void napln_jednorozmerne_pole(const int velkost, int *p_pole)
{
    int i;

    for (i = 0; i < velkost; i++) {
        *p_pole++ = i + 1;
    }
}

int main(int argc, char** argv)
{
    int i;
    int *p_a = vytvor_jednorozmerne_pole(10);
    int **p_p_a = vytvor_viacrozmerne_pole(10, 3);

    napln_jednorozmerne_pole(10, p_a);
    /* vypise obsah jednorozmerneho pola */
    for ( i= 0; i < 10; i++) {
        printf("ulozeno na %d. pozici: %d\n", i, *p_a++);
    }
    free(p_a);
    napln_viacrozmerne_pole(10, 3, p_p_a);
    /* vypise obsah viacrozmerneho pola */
    for (i = 0; i < 10; i++) {
        printf("%d. riadok lava strana: %d, prava strana: %d, velkost: %d\n", i + 1, p_p_a[i][0], p_p_a[i][1], p_p_a[i][2]);
    }
    uvolni_viacrozmerne_pole(p_p_a, 10);

    return (EXIT_SUCCESS); /* staci return 0; */
}
Nahoru Odpovědět  +1 7.4.2015 18:51
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
igimas
Člen
Avatar
igimas:

Díky moc, teď už to určitě zvládnu :-)

 
Nahoru Odpovědět 7.4.2015 21:10
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 18 zpráv z 18.