Deklaracja zmiennych wskaźnikowych

Bash, C, C++, Java, PHP, Ruby, GTK, Qt i wiele innych - wszystko tutaj.
tomeks91
Piegowaty Guziec
Piegowaty Guziec
Posty: 26
Rejestracja: 07 paź 2010, 21:04
Płeć: Mężczyzna
Wersja Ubuntu: 10.04
Środowisko graficzne: GNOME
Architektura: x86

Deklaracja zmiennych wskaźnikowych

Post autor: tomeks91 »

Czy

Kod: Zaznacz cały

char** t
znaczy to samo co

Kod: Zaznacz cały

char **t
i

Kod: Zaznacz cały

char * t[]
Proszę o szybką odpowiedź i wyrozumiałość.
Awatar użytkownika
DDAroo
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 107
Rejestracja: 27 cze 2009, 10:47
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: KDE Plasma
Architektura: x86
Lokalizacja: Kraków
Kontakt:

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: DDAroo »

dokładnie tak
tomeks91
Piegowaty Guziec
Piegowaty Guziec
Posty: 26
Rejestracja: 07 paź 2010, 21:04
Płeć: Mężczyzna
Wersja Ubuntu: 10.04
Środowisko graficzne: GNOME
Architektura: x86

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: tomeks91 »

Świetnie dzięki a czy mógłbyś wytłumaczyć to jest tablica, w której znajdują się wskaźniki?
Czy może wskaźnik do tablicy wskaźników( czyli jeden wskaźnik). Czy jeszcze coś innego?
Czocher
Piegowaty Guziec
Piegowaty Guziec
Posty: 8
Rejestracja: 09 lut 2006, 22:05
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: GNOME
Kontakt:

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: Czocher »

Z tego co mi wiadomo to wskaźnik na wskaźnik.
Awatar użytkownika
DDAroo
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 107
Rejestracja: 27 cze 2009, 10:47
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: KDE Plasma
Architektura: x86
Lokalizacja: Kraków
Kontakt:

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: DDAroo »

tak, jest to wskaźnik na wskaźnik na char, którego można użyć jako:

1) tablica wskaźników (używa się jej do konstrukcji tablic dwuwymiarowych)
2) wskażnik na tablicę char-ów

Wskaźnik na tablicę wskaźników miałby trzy * .
tomeks91
Piegowaty Guziec
Piegowaty Guziec
Posty: 26
Rejestracja: 07 paź 2010, 21:04
Płeć: Mężczyzna
Wersja Ubuntu: 10.04
Środowisko graficzne: GNOME
Architektura: x86

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: tomeks91 »

Czyli w sensie używania pamięci to jest to dokładnie to samo? Chyba powinno być skoro to samo polecenie.

[edit] A z tym 2 to ten wskaźnik to jest inaczej tablica? Czyli inaczej mówiąc na ile adresów będzie to wskazywało na jeden, czy na każdy element z tej tablicy char z osobna?
Awatar użytkownika
DDAroo
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 107
Rejestracja: 27 cze 2009, 10:47
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: KDE Plasma
Architektura: x86
Lokalizacja: Kraków
Kontakt:

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: DDAroo »

Wskaźnik zawsze wskazuje na jeden adres. Pamiętaj, że tablica w C/C++ to jest wskaźnik na pierwszy element, więc do elementów tablicy można się odwoływać albo przez operacje na wskaźnikach albo operator dostępu []. De facto operator [] jest tłumaczony na operacje na wskaźnikach, a wprowadzono go, żeby dostęp do elementów tablicy był bardziej przyjazny dla programistów.

Krótki program pokazujący kilka użyć wskaźników, mam nadzieję, że Ci pomoże:

Kod: Zaznacz cały

#include<iostream>

using namespace std;
int main()
{
	// * - operator wyłuskania, zwraca wartość znajdującą się pod adresem wskazywanym przez wskaźnik
	// & - operator adresu, zwraca adres zmiennej
	int liczba = 5;
	int * pLiczba = &liczba; // pLiczba wskazuje teraz adres zmiennej liczba

	// t1 jest typu const char *
	char t1[] = "ala ma kota";
	char * t2 = t1;

	cout << "druga litera, używajac operatora tablicowego: " << t2[1] << endl;
	cout << "druga litera, używajac operacji na wskaznikach: " << *(t1 + 1) << endl << endl;

	if( &(t2[0]) == t2)
	{
		cout << "adres pierwszego elementu w tablicy to wartosc wskaznika"  << endl << endl;
	}
	// t1 i t2 to wskazniki na pierwszy element tablicy, wiec:
	cout << "pierwszy element tablicy to: " << *t1 << endl;

	// wskaznik na wskaznik na char
	char ** p;

	// adres wskaźnika wskazującego na pierwszy element tablicy to:
	p = &( t2 );

	// tak nie można, bo t1 jest const
	// p = &( t1 );

	cout << "pierwszy element w tablicy przy uzyciu wskaznika na wskaznik: " << **p << endl;
	cout << "drugi element w tablicy przy uzyciu wskaznika na wskaznik: " << *(*p + 1) << endl;
	cout << "drugi element w tablicy przy uzyciu wskaznika na wskaznik i operatora dostępu do tablicy: " << (*p)[1] << endl;

	int c;
	cin >> c;

	return 0;
}
tomeks91
Piegowaty Guziec
Piegowaty Guziec
Posty: 26
Rejestracja: 07 paź 2010, 21:04
Płeć: Mężczyzna
Wersja Ubuntu: 10.04
Środowisko graficzne: GNOME
Architektura: x86

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: tomeks91 »

Dzięki wielkie pomogło ;)

Jeszcze tak czy jak mamy ten przypadek 2) czyli wskaźnik na tablicę char-ów to przypadkiem nie powinniśmy napisać to tak:

Kod: Zaznacz cały

 char (*t)[] 

, bo chyba

Kod: Zaznacz cały

 char *t[] 
nie może oznaczać wskaźnika na tablicę char-ów? tylko tablicę o elementach wskaźnik do char.

Może jednak jest tak, że te zapisy są równoważne?
Awatar użytkownika
DDAroo
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 107
Rejestracja: 27 cze 2009, 10:47
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: KDE Plasma
Architektura: x86
Lokalizacja: Kraków
Kontakt:

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: DDAroo »

Kod: Zaznacz cały

char (*t)[] - wskaźnik na tablicę char-ów
char *t[] - tablica wskaźników na char
Na wikipedii znajdziesz więcej deklaracji wskaźników w części "Możliwe deklaracje wskaźników" : http://pl.wikibooks.org/wiki/C/Wskaźniki
tomeks91
Piegowaty Guziec
Piegowaty Guziec
Posty: 26
Rejestracja: 07 paź 2010, 21:04
Płeć: Mężczyzna
Wersja Ubuntu: 10.04
Środowisko graficzne: GNOME
Architektura: x86

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: tomeks91 »

Czy moje pytanie jest niezrozumiałe? Chciałem się dowiedzieć, jak jest, wikipedię przeczytam, ale tam mi na pytanie nikt nie odpowie.
Awatar użytkownika
DDAroo
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 107
Rejestracja: 27 cze 2009, 10:47
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: KDE Plasma
Architektura: x86
Lokalizacja: Kraków
Kontakt:

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: DDAroo »

To nie jest to samo. Wskaźnika na tablicę można użyć do konstrukcji tablicy dwuwymiarowej w ten sposób:

Kod: Zaznacz cały

int (*tablica)[3] = malloc(liczb_wierszy * sizeof(int[3]));
tablica[2][2] = 23;
Tablica będzie wtedy zajmować ciągły obszar pamięci;

Tablicy wskaźników do konstrukcji tablicy dwuwymiarowej używa się w ten sposób:

Kod: Zaznacz cały

int *tablica[5];
for(i = 0; i < 5; i++)
    tablica[i] = malloc(liczba_kolumn * sizeof(int));

tablica[2][2] = 55;
Tablica będzie wtedy nieciągła w pamięci. Istnieje jeszcze kilka innych sposobów konstrukcji i obsługi dynamicznej tablicy dwuwymiarowej :-P
tomeks91
Piegowaty Guziec
Piegowaty Guziec
Posty: 26
Rejestracja: 07 paź 2010, 21:04
Płeć: Mężczyzna
Wersja Ubuntu: 10.04
Środowisko graficzne: GNOME
Architektura: x86

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: tomeks91 »

To co napisałeś ostatnio znów sporo mi wyjaśniło, mimo wszystko moja wiedza na temat wskaźników jest bardzo nieprzewidywalna, po prostu raz można napisać tak raz tak. Na wykładzie miałem takie coś:

Kod: Zaznacz cały

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

#include "strbib.h"

int
main (int argc, char **argv)
{
  FILE *in = argc > 1 ? fopen (argv[1], "r") : stdin;

  char imie[1024];
  char nazw[1024];
  int lp;

  char *elista[10000];
  int n = 0;
  int i;

  if (in == NULL)
    return 1;

  while (fscanf (in, "%s %s %d", imie, nazw, &lp) == 3) {
    char *nowenazwisko = malloc (strlen (nazw) + 1);
    strcpy (nowenazwisko, nazw);
    elista[n++] = nowenazwisko;
  }

  sort (elista, n);

  for (i = 0; i < n; i++)
    printf ("nazwisko nr %d: %s\n", i, elista[i]);

  return 0;
}

Mam kilka pytań. elista według wikipedii i książek powinna być tablicą wskaźników. Skoro tak to rozpatrując elista[n] czyli wskaźnik typu char* to po drugiej stronie równości mamy nowenazwisko, które jako nazwa wskaźnika powinna wskazać adres tego na co wskazuje czyli na to miejsce, które przydziela malloc?
Awatar użytkownika
DDAroo
Serdeczny Borsuk
Serdeczny Borsuk
Posty: 107
Rejestracja: 27 cze 2009, 10:47
Płeć: Mężczyzna
Wersja Ubuntu: 11.04
Środowisko graficzne: KDE Plasma
Architektura: x86
Lokalizacja: Kraków
Kontakt:

Odp: Deklaracja zmiennych wskaźnikowych

Post autor: DDAroo »

tomeks91 pisze: Skoro tak to rozpatrując elista[n] czyli wskaźnik typu char* to po drugiej stronie równości mamy nowenazwisko, które jako nazwa wskaźnika powinna wskazać adres tego na co wskazuje czyli na to miejsce, które przydziela malloc?
Dokładnie, wskazuje na adres pamięci, który został zwrócony przez malloc. W ten adres później jest kopiowane nazwisko z użyciem funkcji strcpy (nowenazwisko, nazw).

Wskaźnik to nic innego jak połączenie adresu i rozmiaru. Dodając i odejmując liczby do wskaźników poruszamy się w pamięci o określony dla typu wskaźnika rozmiar. np. dla char * poruszamy się o 1, a dla int * o 4. Jedynie void * nie ma ustalonego rozmiaru i dlatego nie można do niego nic dodawać ani odejmować.

Program ilustrujący manipulację wskaźnikami:

Kod: Zaznacz cały

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

typedef struct
{
  int wiek;
  char imie[12]; // 12 bajtów zarezerwowane na imię
} Student;

// zakładamy, że program jest kompilowany na 32 bitowej maszynie z rozmiarem int-a = 4 i shorta = 2

int main(int argc, char ** argv)
{
  // przydzielamy pamięć na dwóch studentów
  Student * studenci = (Student *) malloc(sizeof(Student) * 2); // rozmiar struktury Student*2
  /*
   * Nasza pamięć wygląda następująco:
   * 
   * wiek - 4 bajty <-- adres pierwszego studenta
   * imie - 12 bajtów
   * wiek - 4 bajty <-- adres drugiego studenta
   * imie - 12 bajtów
   */
  // przykładowe dane 
  studenci[0].wiek = 23;
  strcpy(studenci[0].imie, "Piotr");
  studenci[1].wiek = 19;
  strcpy(studenci[1].imie, "Nikodem");
  // wskaźniki będą nam potrzebne do zabawy
  char * adres_pierwszego = (char *) (studenci);
  int * adres_drugiego = (int *) &(studenci[1]);
  // studenci wskazuje na początek tablicy, pozycja imienia pierwszego studenta ma adres: studenci + rozmiar int
  // char ma rozmiar 1 bajta, więc używając char * jako wskaźnika poruszamy się po jednym bajcie
  char * pierwsze_imie = adres_pierwszego + 4;
  // tym razem używając wskaźnika na int będziemy się poruszać o 4 bajty w adresach pamięci
  char * drugie_imie = (char *) (adres_drugiego + 1);
  printf("pierwsze imie: %s, drugie imie = %s\n", pierwsze_imie, drugie_imie);
  
  
  // aby dostać się do wieku pierwszego studenta z adresu drugiego musimy się cofnąć o 12 + 4 = 16 bajtów
  // poruszamy się o 4 bajty (wskaźnik na int), więc musimy się cofnąć o 4, aby przesunąć się w pamięci o 16 bajtów
  int wiek_pierwszego = (int) *(adres_drugiego - 4);
  // aby dostać się do wieku drugiego studenta z adresu pierwszego musimy się przesunąć do przodu o  4 + 12 = 16 bajtów
  // poruszamy się po 1 bajcie tym razem (wskaźnik na char)
  int wiek_drugiego = (int) *(adres_pierwszego + 16);
  printf("wiek pierwszego: %d, wiek drugiego = %d\n", wiek_pierwszego, wiek_drugiego);
  
  short * adr_pierwsz = (short *) (studenci);
  // rozmiar short to 2 bajty więc używając wskaźnika short * poruszamy się o 2 bajty w pamięci
  // chcemy przesunąć się w pamięci o 4 + 12 + 4 bajty = 20 bajtów
  char * imie = (char *) (adr_pierwsz + 10);
  printf("drugie imie: %s\n", imie);
  
  // zwolnij pamięć
  free(studenci);
 
  return 0;
}

ODPOWIEDZ

Wróć do „Programowanie”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość