Autor Wątek: [C] podwójny wskaźnik, tablica parametr blabla:P  (Przeczytany 3514 razy)

Offline .Dexter.

  • Użytkownik

# Styczeń 27, 2011, 17:17:10
Chciałbym stworzyć procedurę, która tworzy mi tablicę i zwraca ją na zewnątrz, ale nie przez wartość, a przez wskaźnik. (zauważyłem zadanie na wskaźnikach, wydało mi się ciekawe i nie mogę go rozgryźć :/).
Czyli mam tak:
void foo(int **tab)
{
int n;
scanf("%d",&n); //ilu elementowa tablice tworzymy
*tab=(int**)malloc(sizeof(int)*n);
...
}
problem jest w tym, że raz że nie wiem jak wczytać poprawnie elementy takiej tablicy, a dwa że nie wiem czy poprawnie ją wywołuję:
//wczytywanie
for(int i=0;i<n;++i)
{
scanf("%d",&val); //nie wiedzialem jakie dac operatory :P
*tab[i]=val; //dlatego naokolo
}

//wukorzystanie:

int main()
{
int *tablica;
foo(&tablica);
for(int i=0;i<sizeof(tablica);++i) //wypisywanie elementow
{
printf("%d\n",tablica[i]);
}
free(tablica); //zwalnianie pamieci
return 0;
}

Mógłby jakiś dobry człowiek mi powiedzieć gdzie robię błąd?

EDIT:
To forum jest genialne, tylko napiszę post i zaraz znajduję rozwiązanie:
#include <stdio.h>

void S(int **tab,int *s)
{
int k,w;

scanf("%d",&k);
fflush(stdin);
*tab=(int**)malloc(sizeof(int) * k);

int i;
for(i=0;i<k;i++)
{
fflush(stdin);
scanf("%d",&w);
fflush(stdin);
(*tab)[i]=w;
}
*s=k;



}




int main()
{
int *t,i,n;
t=NULL;
S(&t,&n);

if(t!=NULL)
{
for(i=0;i<n;i++)
{
printf("%d\n",t[i]);
}
}
free(t);

return 0;
}
:D
« Ostatnia zmiana: Styczeń 27, 2011, 17:35:53 wysłana przez .Dexter. »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Lerhes

  • Użytkownik

# Styczeń 27, 2011, 17:44:57
Już na dzień dobry źle ją utworzyłeś.
Mamy tablicę w C++ którą pokazujemy wskaźnikiem. Załóżmy że ten typ to int. Więc na tę tablicę pokazali byśmy wskaźnikiem : int * wsk;

A teraz ty chcesz zrobić tablicę, która będzie przechowywać takie wskaźniki. Jak będzie wyglądał wskaźnik na tablicę ze wskaźnikami?
int ** wskNaWsk;

No to zarezerwujmy na tę tablicę wskaźników miejsce:
wskNaWsk = (int**) malloc(sizeof(int *) * n );

No dobrze, ale teraz tę tablicę i w niej będziemy trzymać wskaźniki na tablice, ale teraz które tablice ? Na razie ich nie ma! Trzeba je utworzyć!

for(int i = 0 ; i < n ; i++)
{
wskNaWsk[i] = (int*) malloc(sizeof(int) * m );
}

No i można już używać. Podobnie to zwalniamy.

Całość:
int ** wskNaWsk;
int n = 10;
wskNaWsk = (int**) malloc(sizeof(int *) * n );
int m = 100;
for(int i = 0 ; i < n ; i++)
{
wskNaWsk[i] = (int*) malloc(sizeof(int) * m );
}
wskNaWsk[0][0] = 50;

for(int i = 0 ; i < n ; i++)
{
free(wskNaWsk[i]);
}
free( wskNaWsk );

Edit:
A ty nie chcesz tablicy dwuwymiarowej tylko jednowymiarową?
No to po prostu:
void foo(int *tab)
{
int n;
scanf("%d",&n); //ilu elementowa tablice tworzymy
tab=(int*)malloc(sizeof(int)*n);
}
Pamiętaj tylko o free.

Lerhes
« Ostatnia zmiana: Styczeń 27, 2011, 17:46:39 wysłana przez Lerhes »

Offline ArekBal

  • Użytkownik

# Styczeń 27, 2011, 18:34:27
Ale takiej procedury nie trzeba tworzyć... ona już jest i się nazywa new, albo malloc w zależności od potrzeb.

Offline Xirdus

  • Moderator

# Styczeń 27, 2011, 18:57:17
Ale takiej procedury nie trzeba tworzyć... ona już jest i się nazywa new
W C++. A tu jest C.

Offline .Dexter.

  • Użytkownik

# Styczeń 28, 2011, 11:13:07
Edit:
A ty nie chcesz tablicy dwuwymiarowej tylko jednowymiarową?
No to po prostu:
void foo(int *tab)
{
int n;
scanf("%d",&n); //ilu elementowa tablice tworzymy
tab=(int*)malloc(sizeof(int)*n);
}
Pamiętaj tylko o free.

Lerhes
A nie trzeba tu tak jak zrobiłem podwójnego wskaźnika? Nazwa tablicy to przecież wskaźnik, więc żeby przez parametr ją zmodyfikować (przekazać) to chyba muszę zrobić ** ?
Chodzi mi o to, że jak dam:
int *a;
i mam void foo(int *a);
to jak zrobię
foo(a); to mi nie zmodyfikuje a,
muszę mieć
void foo(int **a);
Gdzie się mylę?

Offline Lerhes

  • Użytkownik

# Styczeń 28, 2011, 12:49:59
Mylisz się (ale to zależy co chcesz modyfikować).
Traktuj wskaźniki, tak jak powinieneś je traktować.
Dopiszę swoje własne komentarze do twoich (adresy podane jako przykładowe (skrócone dla wygody)):

Edit: Jednak bez znaczników code czyta się lepiej.

int *a;
//Teraz w "a" mamy adres pamięci 3832 gdzie jest jakaś zmienna typu int (pod tym adresem).
i mam void foo(int *a);

//Przekazujesz przesz kopiowanie (no bo wywołujemy funkcję, a tutaj argumenty są kopiowane) nasz wskaźnik "a".
//Czyli co zostaje skopiowane do funkcji foo? Wartość tego "a" czyli 3832.

to jak zrobię
foo(a); to mi nie zmodyfikuje a,

//Racja, samego "a" ci nie zmodyfikuje. W "a" jest adres 3832 i do widzenia, nie możesz go zmienić, został skopiowany do funkcji...
//Ale to na co pokazuje "a" -> czyli to co znajduje się pod adresem 3832 (int) możesz modyfikować, bo masz jego adres.
//Więc *a = 100; zmodyfikuje to co jest pod adresem 3832 -> będzie tam teraz 100.
//Jak opuścisz funkcję foo(), wtedy "a" nadal będzie zawierać wartość 3832 -> tego nie udało Ci się zmienić,
//bo nie mogłeś, ale to na co pokazuje "a" to teraz 100.

muszę mieć
void foo(int **a);

//Jeżeli zrobisz tak, to teraz możesz zrobić w kodzie też tak:
//Gdzieś tam deklaracja funkcji
void foo(int **a);
int *a;
//Wywołanie foo
void foo(&a);

//Teraz w Ciele funkcji foo, możemy zmienić to na co pokazuje "a", czyli adres który znajduje się w "a":
*a = (int *) 8392;
//Teraz poza funkcją foo, "a" będzie pokazywać na adres 8392, chociaż wcześniej pokazywało na 3832.
//To co znajduje się pod tym adresem, to zupełnie inna historia.

Mam nadzieję, że trochę rozjaśniłem.
#Jeszcze raz edit:
void foo(int *tab)
{
int n;
scanf("%d",&n); //ilu elementowa tablice tworzymy
tab=(int*)malloc(sizeof(int)*n);
}
Jasne że ten kod jest źle... Wskaźnik wcale nie zostanie przepisany, będzie lipa a nie nadanie tab nowej wartości adresu.
void foo(int **tab)
{
int n;
scanf("%d",&n); //ilu elementowa tablice tworzymy
*tab=(int*)malloc(sizeof(int)*n);
}
Użycie:
int * a = 0;
foo(&a);
//Dalej jak normalna tablice
a[0] = 19;
Więc generalnie, wymądrzam się dużo tylko że błędnie. Miałeś rację, w przypadku zastosowanym przez Ciebie, trzeba zrobić podwójny wskaźnik. Nie sprawdziłem tego kodu za pierwszym razem, bo mi się nie chciało, to czasami zapomni się o czymś ważnym. Najlepiej traktować wskaźniki tak jak należy: jako adresy -> czyli też liczbę.

#Edit :)
Nie to że się nie da, wszystko w C++ się da. Tylko za taki kod, dostaniesz po łapach :P
void foo(int *tab)
{
int n;
scanf("%d",&n); //ilu elementowa tablice tworzymy
//Tutaj nie trzeba tej zmiennej zapasowej ll -> zostawilem dla latwiejszego zrozumienia
int * ll = (int *)malloc(sizeof(int)*n);
(*tab) = (unsigned int)ll;
//Krocej:
//(*tab) = (unsigned int)malloc(sizeof(int)*n);
}
Użycie:
int * a = 0;
foo((int *)&a);
a[0] = 997;
Lerhes
« Ostatnia zmiana: Styczeń 28, 2011, 13:31:39 wysłana przez Lerhes »

Offline .Dexter.

  • Użytkownik

# Styczeń 28, 2011, 15:18:18
Dzięki, wszystko już jasne :)
Mam nadzieję, że teraz w C++ z referencjami nie będzie już takiego problemu :P

Offline ArekBal

  • Użytkownik

# Styczeń 28, 2011, 18:49:25
Nie łudź się... będzie dużo problemów.
Ale jak juz przeskoczysz, przyjmiesz jakieś schematy(tak jak i w c) to będzie banalniej i przyjemniej.