• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Kilka pytań C

VPS Starter Arubacloud
0 głosów
314 wizyt
pytanie zadane 5 września 2015 w C i C++ przez mrcnsct Nałogowiec (36,390 p.)
edycja 5 września 2015 przez mrcnsct

Witam. Mam kilka pytań:

1. wskaźnik wskaźnika:

int **tab;

Do czego w takim wypadku odnosi się:

tab;
*tab;
**tab;

2. strncpy

char napis[20];
strncpy(napis, "tekst", sizeof napis-1);
napis[sizeof napis -1] = 0;

Dlaczego sizeof napis-1, a nie sizeof napis?

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 int main(int argc, const char **argv) {
   char haslo_poprawne = 0;
   char haslo[16];
   
   if (argc!=2) {
     fprintf(stderr, "uzycie: %s haslo", argv[0]);
     return EXIT_FAILURE;
   }
   
   strncpy(haslo, argv[1], sizeof(haslo) - strlen(haslo) - 1);
   haslo[sizeof haslo - 1] = '\0';
   if (!strcmp(haslo, "poprawne")) {
     haslo_poprawne = 1;
   }
   
   if (!haslo_poprawne) {
     fputs("Podales bledne haslo.\n", stderr);
     return EXIT_FAILURE;
   }
   
   puts("Witaj, wprowadziles poprawne haslo.");
   return EXIT_SUCCESS;
 }

Dlaczego sizeof(haslo) - strlen(haslo) - 1? (14 linijka)

3. UCS-2

#include <stdio.h>
#include <stddef.h>
#include <stddef.h>

int main(){

    wchar_t* wcs1 = L"Ala ma kota.";
    wchar_t* wcs2 = L"Kot ma Ale.";
    wchar_t calosc[25];
    wcscpy(calosc, wcs1);
    *(calosc + wcslen(wcs1)) = L' ';
    wcscpy(calosc + wcslen(wcs1) + 1, wcs2);
    printf("lancuch wyjsciowy: %ls\n", calosc);

    return 0;
}

Co oznaczają linijki 11 i 12?

Proszę o pomoc.

2 odpowiedzi

+1 głos
odpowiedź 6 września 2015 przez MrWeb Stary wyjadacz (10,200 p.)
wybrane 6 września 2015 przez mrcnsct
 
Najlepsza

1. wskaźnik wskaźnika:

int **tab;

Do czego w takim wypadku odnosi się:

tab;

*tab;

**tab;

Ten zapis jest trochę błędny, bo przy rozróżnianiu wskaźników powinieneś użyć też typu, bo ma on znaczenie.

więc w tym przykładzie:

int tab1;

To jest zwykła zmienna typu int. Jest ona tworzona na stosie i jest niszczona gdy program wyjdzie poza zakres {} klamerek czyli np. poza zakres jakiejś funkcji. Może przechowywać wartości takie jak: -5, 10, 999. Dokładny zakres wartości którą może przechowywać jest zależny od architektury procesora.


int *tab2;

To jest wskaźnik na zmienną typu int. Jest on tworzony na stosie i jest niszczony gdy program wyjdzie poza zakres {} klamerek czyli np. poza zakres jakiejś funkcji. Może przechowywać wartości takie jak: 0xEE1279CA. Dokładny zakres wartości którą może przechowywać jest zależny od architektury procesora.

Taki wskaźnik może wskazywać na zmienną typu int, ale może też wskazywać na początek tablicy typów int.

// tworzenie tablicy dynamicznej składającej się z 10 intów.
int *tab2 = malloc(sizeof(int) * 10);
free(tab2); //gdzieś dalej w programie.

Podobny wskaźnik, ale o typie char* może wskazywać na tablicę charów, czyli na tekst.

char *tab2 = "jakis tekst";

int **tab3;

To jest wskaźnik na wskaźnik który wskazuje na zmienną typu int. Jest on tworzony na stosie i jest niszczony gdy program wyjdzie poza zakres {} klamerek czyli np. poza zakres jakiejś funkcji. Może przechowywać wartości takie jak: 0xEE1279CA. Dokładny zakres wartości którą może przechowywać jest zależny od architektury procesora.

Taki typ potrafi przechowywać inny wskaźnik lub tablicę wskaźników


Mam nadzieję, że o takie wyjaśnienie Ci chodziło. Po więcej informacji odsyłam do książek o języku C.


 

2. strncpy

char napis[20];
strncpy(napis, "tekst", sizeof napis-1);
napis[sizeof napis -1] = 0;

Dlaczego sizeof napis-1, a nie sizeof napis?

linia 1: tworzona jest tablica dwudziestu zmiennych typu char. (oczywiście indeksowane od 0 do 19).

linia 2: wykorzystano tu bezpieczne kopiowanie (funkcja strncpy - http://www.cplusplus.com/reference/cstring/strncpy/). Cała ta linia to poprostu wydanie takiego polecenia: skopiuj sizeof(napis)-1 znaków z tekstu "tekst" do tablicy napis. Dzięki dodatkowemu parametrowi (sizeof(napis)-1) mamy pewność, że zakres tablicy napis nie zostanie przekroczony - nie wystąpi buffer overflow.

linia 3: zerujemy ostatni bajt tablicy. sizeof(napis) - 1  bo sizeof(napis) zwróci 20, a tablice są indeksowane od zera więc nie ma komórki napis[20]. Najdalszą jest napis[19]. Ten -1 zapewnia, że odwołujemy sie do ostatniej komórki tablicy.

Zerujemy, bo tablice tekstowe muszą się kończyć zerem.

 

To samo w linii 14 w następnym listingu.

strncpy(haslo, argv[1], sizeof(haslo) - strlen(haslo) - 1);

To jest bezpieczne kopiowanie z argv[1] (argumentu który przekazujemy przy uruchomieniu programu z konsoli).

Niestety nie rozumiem dlaczego jest tam strlen(haslo). Ta tablica jest niezainicjalizowana więc nie wiem dlaczego użyte jest liczenie długości stringa.


3. UCS-2

#include <stdio.h>
#include <stddef.h>
#include <stddef.h>
 
int main(){
 
    wchar_t* wcs1 = L"Ala ma kota.";
    wchar_t* wcs2 = L"Kot ma Ale.";
    wchar_t calosc[25];
    wcscpy(calosc, wcs1);
    *(calosc + wcslen(wcs1)) = L' ';
    wcscpy(calosc + wcslen(wcs1) + 1, wcs2);
    printf("lancuch wyjsciowy: %ls\n", calosc);
 
    return 0;
}

Co oznaczają linijki 11 i 12?

*(calosc + wcslen(wcs1)) = L' ';

Linia 11 wpisuje spację (rzutowaną na wchar_t) do tablicy calosc pod indeksem wsclen(wsc1). Gdzie wsclen(wsc1) będzie wartość określająca długość stringu wskazywanego przez wskaźnik wsc1.

W tym przypadku, to po prostu znaczy calosc[12] = ' ';


wcscpy(calosc + wcslen(wcs1) + 1, wcs2);

Ten kod odpowiada za skopiowanie całego napisu z pod wskaźnika wsc2 do tablicy calosc pod indeksem wsclen(wsc1) + 1. Ponieważ wsclen(wsc1) zwróci 12, to ta linia po prostu dopisze tekst z pod wskaźnika wsc2 do tablicy calosc zaczynając od indeksu 13.

komentarz 6 września 2015 przez mrcnsct Nałogowiec (36,390 p.)

Dziękuję. Co do pierwszego to chodzi mi o to, że 

int *a;
int x=5;
a=&x;
printf("adres %p, wartość pod tym adresem %d",a,*a);

a to wskaźnik, zmienna zawierająca adres, *a to wartość pod tym adresem.

int **b;
b=?;
*b=?;
**b=?;

Chodzi mi o to czym w takim wypadku jest b, czy zawiera adres tego wskaźnika na wskaźnik? Co zawiera *b i **b? Czy *b to wartość pod adresem wskaźnika na wskaźnik na zmienną typu int, a **b to wartość pod adresem wskaźnika na zmienną typu int?

komentarz 6 września 2015 przez MrWeb Stary wyjadacz (10,200 p.)
int **b; // to jest wskaźnik na wskaźnik na int.

b=?; // tutaj przypisujesz na co ma ten wskaźnik wskazywać.

*b=?; // tutaj ustawiasz wskaźnik, na który wskazuje b. 

**b=?; // tutaj ustawiasz wartość pod wskaźnikiem na który wskazuje b.



Inny przykład:

int cukierki;

int* wsk1;

int** wsk2;



cukierki = 5; // ustawiam zmienną

wsk1 = &cukierki; // ustawiam pierwszy wskaźnik. wsk1 "pokazuje palcem" na adres cukierki

wsk2 = &wsk1; // ustawiam drugi wskaźnik. wsk2 "pokazuje palcem" na adres wsk1



wsk2 = ? // tutaj mógłbym zmienić to, na co wskazuje wsk2, np na inny wskaźnik.

*wsk2 = ? // to odwołanie wyciąga wskaźnik na który wskazuje wsk2. 

               // czyli jest jednoznaczne z poniższym zapisem

wsk1 = ? // to samo co *wsk2 = ?

**wsk2 = ? // tutaj mógłbym ustawić to, na co wskazuje wskaźnik, na który wskazuje wsk2. W tym przypadku jest to zmienna cukierki więc **wsk2 = 6 ustawi zmienną cukierki na 6.

 

Wskaźniki są proste, ale trzeba je dobrze zrozumieć, żeby można je było używać w wielu wymiarach czyli w konstrukcjach takich jak int **wsk2.

Wg mnie łatwiej jest użyć jakiegoś kontenera np std::array :)

komentarz 6 września 2015 przez mrcnsct Nałogowiec (36,390 p.)
Dziękuję za pomoc.
+1 głos
odpowiedź 5 września 2015 przez adrian17 Ekspert (344,100 p.)

Co do 2:

char napis[20];
strncpy(napis, "tekst", sizeof napis-1);
napis[sizeof napis -1] = 0;

W tym przypadku to akurat nie jest konieczne, ale ogólnie: gdyby źródło było dłuższe od tablicy do której kopiujemy, kopiując (sizeof napis) znaków, przekopiowalibyśmy też 20sty znak. Ale nie ma potrzeby tego robić, skoro C-string i tak musi być zakończony zerem; tak więc kopiujemy 19 znaków, a w 20stym wstawiamy 0.

strncpy(haslo, argv[1], sizeof(haslo) - strlen(haslo) - 1);

Na oko to błąd, bo strlen(haslo) nie ma tu sensu.

komentarz 5 września 2015 przez mrcnsct Nałogowiec (36,390 p.)

A gdyby było 

char napis[20];
strncpy(napis, "tekst", sizeof napis);
napis[sizeof napis] = 0;

byłoby źle? Co do drugiego to też mi się wydaje to dziwne, ale tak jest na Wikibooks, w kursie C.

komentarz 5 września 2015 przez adrian17 Ekspert (344,100 p.)
Tu trzecia linia byłaby zła, bo napis[sizeof napis] wychodziłoby poza rozmiar tablicy.
komentarz 5 września 2015 przez mrcnsct Nałogowiec (36,390 p.)
Czyli ile wynosi sizeof napis 19 czy 20?
komentarz 5 września 2015 przez adrian17 Ekspert (344,100 p.)
sizeof napis w tym przypadku wynosi 20.
komentarz 5 września 2015 przez mrcnsct Nałogowiec (36,390 p.)
Rozumiem, a napis[20] nie istnieje, bo jest numerowanie od 0, dzięki.

Podobne pytania

0 głosów
0 odpowiedzi 208 wizyt
pytanie zadane 16 grudnia 2016 w C i C++ przez programmero Bywalec (2,420 p.)
0 głosów
1 odpowiedź 176 wizyt
pytanie zadane 15 grudnia 2016 w C i C++ przez programmero Bywalec (2,420 p.)
+3 głosów
3 odpowiedzi 828 wizyt
pytanie zadane 23 sierpnia 2015 w C i C++ przez Patrycjerz Mędrzec (192,340 p.)

92,455 zapytań

141,263 odpowiedzi

319,099 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...