Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Zwracanie tablicy dwuwymiarowej z funkcji

Ostatnio zmodyfikowano 2014-01-28 12:49
Autor Wiadomość
Atexor
Temat założony przez niniejszego użytkownika
Zwracanie tablicy dwuwymiarowej z funkcji
» 2014-01-26 19:54:06
Witajcie,
Mam problem z programem, który wypełni macierz 10x10 losowymi wartościami z przedziału [a,b], potem w pierwszej funkcji ją wyświetli i w drugiej także wyświetli, ale zawężoną o losowe współrzędne.

Dokładnie to nie wiem jak mam zwrócić tablicę z funkcji "wys" do głównej funkcji programu, aby z powrotem ją dać do innej funkcji. Przy sprawdzaniu czy dobrze zwróciło do funkcji int main() (na dole kodu) pokazuje mi duże liczby w macierzy zamiast tę samą macierz. Jak to naprawić?

Kod (bez drugiej funkcji, bo na razie niepotrzebna):
C/C++
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
typedef int MAC[ 10 ][ 10 ];

int wys( int af, int bf, int Nf )
{
    int j, k;
    int macierz[ 10 ][ 10 ];
    for( j = 0; j < Nf; j++ ) // losowanie wartosci dla macierzy NxN
    {
        for( k = 0; k < Nf; k++ )
        {
            macierz[ j ][ k ] = af + rand() %( int )( bf - af + 1 );
            printf( "\t%d", macierz[ j ][ k ] );
        }
        printf( "\n\n" );
    }
    return( macierz[ 10 ][ 10 ] );
}

int main()
{
    srand( time( NULL ) );
    float liczba, a, b, x;
    int i, j, k, N, ilosc;
    float tab[ 15 ];
   
    for( i = 0; i < 10; i++ ) //generuje a i b z przedzialu [0,15]
    {
        tab[ i ] = rand() % 15;
        if( i == 0 )
        {
            a = tab[ i ];
            b = tab[ i ];
        }
        if( a > tab[ i ] )
             a = tab[ i ];
       
        if( b < tab[ i ] )
             b = tab[ i ];
       
    }
   
    printf( "Jaka macierz NxN chcesz wyswietlic?   " );
    scanf( "%d", & N );
    puts( "\n" );
   
    MAC mactab;
    mactab[ 10 ][ 10 ] = wys( a, b, N );
    printf( "\n\n" );
   
    for( i = 0; i < N; i++ )
    // ------------------------tutaj zle wyswietla mi tablice ktora zwrocil z funkcji wys---------------------
    {
        for( j = 0; j < N; j++ )
        {
            printf( "%d\t", mactab[ i ][ j ] );
        }
        printf( "\n\n" );
    }
   
    system( "PAUSE" );
    return 0;
}

/ cpp ]
P-103280
Monika90
» 2014-01-26 20:25:36
Można zwrócic tablicę z funkcji jak się ją opakuje w strukturę. Można też zwrócić wskaźnik do dynamicznie zaalokowanej tablicy. Ale najlepiej będzie przekazać tablicę do wypełnienia przez referencję:
C/C++
void f( int( & tab )[ 10 ][ 10 ] )
{
    //tu używasz tab zwyczajnie jak każdej innej tablicy
    //to co w niej zapiszesz będzie widoczne w main
}

int main()
{
    int a[ 10 ][ 10 ];
    f( a );
}
P-103285
alixir
» 2014-01-26 20:57:03
Dla wyjaśnienia podam dwa przykłady:

1 - przekazywanie przez wskaźnik (jak tablice jednowymiarowe) oraz symulowanie wielowymiarowości

C/C++
void wypelnijMacierz( int * tab ) {
    for( int i = 0; i < 10; i++ )
    for( int j = 0; j < 10; j++ )
         tab[ i * 10 + j ] = i + j;
   
}
...
int macierz[ 10 ][ 10 ];

wypelnijMacierz( & macierz[ 0 ][ 0 ] );


2 - jak koleżanka wspomniała przez wskaźnik do dynamicznie zaalokowanej tablicy

C/C++
void wypelnijMacierz( int ** tab ) {
    for( int i = 0; i < 10; i++ )
    for( int j = 0; j < 10; j++ )
         tab[ i ][ j ] = i + j;
   
}
...
int ** macierz;

macierz = new int *[ 10 ];
for( int i = 0; i < 10; i++ )
     macierz[ i ] = new int[ 10 ];

wypelnijMacierz( macierz );

for( int i = 0; i < 10; i++ )
     delete[] macierz[ i ];

delete[] macierz;
P-103286
Monika90
» 2014-01-26 21:41:47
Alixir, twój pierwszy przykład ma niezdefiniowane zachowanie.
http://c-faq.com/aryptr​/ary2dfunc2.html
P-103288
Atexor
Temat założony przez niniejszego użytkownika
» 2014-01-26 22:49:04
Super... pisałem długiego posta i przy "Zapisz zmiany" go nie wysłało tylko pokazało temat bez mojej odpowiedzi. Chyba jakiś bug forum , bo już drugi raz mi się to zdarzyło.

----------------
Najogólniej to ja na początku chciałem w funkcji (nie main) stworzyć tablicę, tam na niej operować i ją zwrócić do głównej funkcji main poprzez return, a nie przekazywać ją z main do funkcji. Dałoby radę tak zrobić?

Moniko - próbowałem to zrobić za pomocą Twojego przykładu, jednak wyskakiwał mi błąd. Próbowałem także za pomocą podobnego przykładu do twojego (tylko tam do tablic jednowymiarowych) i też nie działało. Wzorzec: http://wklej.to/GGN4V
W komentarzach zaznaczyłem co nie działa w obu przypadkach:
Kod: http://wklej.to/2sZAk
Czy w Twoim przykładzie zamiast operatora wyłuskania & nie powinno być wskaźnika *?

Spróbowałem też to stworzyć przy pomocy zdefiniowania nowej zmiennej - jak w tym przykładzie http://wklej.to/s40aq.
Kod: http://wklej.to/V3Fdb
Macierz mi wyświetla w konsoli, jednak nie wiem jak tę tablicę zwrócić do funkcji main.

Chciałem także przez struktury jak poleciłaś. Znalazłem na [a href="http://pl.wikibooks.org/wiki/C/Funkcje#Za_pomoc.C4.85_struktur" name"wikibooks"] jak to niby zrobić, ale mi nie działało.
Fragment kodu: http://wklej.to/Qxahj


Alixir - niezbyt rozumiem twoje przykłady.
W pierwszym jako rozmiar tablicy korzystasz z mnożenia i* 10 i dodajesz do tego j, aby uzyskać i+j. Co to w ogóle oznacza?

Zaś w drugim korzystasz ze... wskaźnika na wskaźnik (dwie gwiazdki), new int i delete [] innej tablicy. Nie wiem o co chodzi w tym zapisie. Teoretyczniejak pisałeś jest to rozwiązanie dla dynamicznie zaalokowanej tablicy, jednak nie kojarzę abyś korzystał tam z malloc'a, czy coś w ten deseń. Nie, alokować też jeszcze nie potrafię, dzisiaj próbowałem akurat malloc'ować realloc'ować, ale jak zwykle nie działało. Teraz w ogóle widzę, że nie usunąłem biblioteki limits.h w powyższych moich kodach.
P-103292
Monika90
» 2014-01-27 00:11:21

Moniko - próbowałem to zrobić za pomocą Twojego przykładu, jednak wyskakiwał mi błąd. Próbowałem także za pomocą podobnego przykładu do twojego (tylko tam do tablic jednowymiarowych) i też nie działało. Wzorzec: http://wklej.to/GGN4V
W komentarzach zaznaczyłem co nie działa w obu przypadkach:
Kod: http://wklej.to/2sZAk
Czy w Twoim przykładzie zamiast operatora wyłuskania & nie powinno być wskaźnika *?
Mój przykład jest w C++. W C++ & służy do deklarowania referencji - w C nie ma referencji.

Za pomocą struktury w języku C można tak:
C/C++
#include <stdlib.h>
#include <stdio.h>

typedef struct {
    int macierz[ 10 ][ 10 ];
} s1;

s1 wys( int af, int bf, int Nf )
{
    int j, k;
    s1 s;
    for( j = 0; j < Nf; j++ ) // losowanie wartosci dla macierzy NxN
    {
        for( k = 0; k < Nf; k++ )
        {
            s.macierz[ j ][ k ] = af + rand() %( int )( bf - af + 1 );
            printf( "\t%d", s.macierz[ j ][ k ] );
        }
        printf( "\n\n" );
    }
    return s;
}

int main()
{
    s1 s;
    s = wys( 1, 3, 10 );
}
Takie zwracanie struktury z funkcji oznacza, że jej cała zawartośc jest kopiowana (100 intów), w pewnych sytuacjach to może prowadzić do problemów z wydajnością, ale w takim prostym programiku to raczej nie ma znaczenia.

A w ogóle, radzę Ci przejść na C++.
P-103294
Atexor
Temat założony przez niniejszego użytkownika
» 2014-01-27 00:52:04
Za pierwszym pisaniem mojego poprzedniego postu wspominałem o referencji, gdyż słyszałem o niej, że istnieje jako alternatywa wskaźników z C. Myślałem, że tamten kod napisałaś w języku C, bo nie widziałem żadnych charakterystycznych rzeczy dla C++ typu strumienie itp. Pomyślałem, że poprzez stwierdzenie "referencja" mogłaś mieć na myśli ów wskaźniki, tylko zrobiłaś literówkę pomiędzy & i *.

W międzyczasie jak mi odpisywałaś zrozumiałem już o co chodziło z tym przykładem na wikibooks ze strukturami. Po prostu nie sądziłem, że może istnieć bez etykiety i to mi głównie psuło "szyk". Teraz przeanalizowałem Twój przykład jak wyglądał i z pamięci postarałem się zrobić analogiczny. Działa :)
Dziękuję Ci bardzo!

P.S. Z miłą chęcią bym przeszedł na C++, ale na studiach muszę poznać C, zaś programowaniem obiektowym zajmę się bodajże za dwa semestry.

Pozdrawiam :)
P-103295
alixir
» 2014-01-27 07:23:56
Atexor w swoim pierwszym poście nie zaznaczyłeś, że chodzi ci o rozwiązanie czysto C. Ja z reguły używam C++, stąd też pewne nieporozumienie i niejasność w moim kodzie.

Gwoli wyjaśnienia:
Mój pierwszy przykład opierał się na symulowania wielowymiarowości tablicy, tak jak robią to kompilatory (pamięć jak wiadomo jest liniowa). Monika jednak dobrze zauważyła, że ten sposób ma niezdefiniowane zachowanie w kompilatorach zgodnych ze standardem C99 (nawet nie wiedziałem – mój błąd).
Chodziło tu ogólnie o wyliczanie indeksu ze wzoru:
Nr_indeksu = i * w + j
Gdzie:
i,j - to współrzędne w tablicy dwuwymiarowej
w – szerokości tablicy dwuwymiarowej
W twoim przykładzie (macierz o szerokości 10), gdybyś chciał dostać się do elementu tab[2][6] zapis symulowany wyglądał by tak: tab[2*10+6]

Drugi przykład opierał się o tablice zaalokowane dynamicznie. Nie ma tam zapisu malloc, gdyż zastępuje go napis new (z języka C++)

Pozdrawiam



P-103298
« 1 » 2
  Strona 1 z 2 Następna strona