Wprowadzenie do programowania w języku C Tablice
Transkrypt
Wprowadzenie do programowania w języku C Tablice
Wprowadzenie do programowania w języku C Część piąta Tablice — koncepcja, reprezentacja, przetwarzanie Autor Roman Simiński Kontakt [email protected] www.us.edu.pl/~siminski Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa. Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne. Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione. Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — deklaracja, reprezentacja wewnętrzna Co to jest tablica? Tablica jest zmienną złożoną z elementów tego samego typu. Obejmuje ona ciągły obszar pamięci operacyjnej dokładnie tak duży, aby zmieścić wszystkie jej elementy. Termin tablica w języku potocznym jest zmiennikiem sformułowania zmienna tablicowa. Po co się stosuje tablice? Tablice stosuje się wtedy, gdy trzeba zgromadzić wiele obiektów tego samego typu w jednej strukturze danych, i w sposób wygodny przetwarzać je według jednorodnego schematu. Dwie istotne własności tablic (wg. standardu C89): tablica zawsze składa się z ustalonej, i znanej na etapie kompilacji, liczby elementów, liczba elementów tablicy nie ulega zmianie w trakcie działania programu ― tablice są statyczne. Copyright © Roman Simiński Strona : 2 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — deklaracja, reprezentacja wewnętrzna Deklaracja zmiennych tablicowych Ogólna postać deklaracji tablicy — zmiennej tablicowej: typ_elemetu nazwa_tablicy[ <wyrażenie_ stałe> ] wyrażenie_ stałe — wyrażenie określające liczbę elementów tablicy, wartość tego wyrażenia musi być znana na etapie kompilacji. Dziesięcioelementowa tablica liczb całkowitych Różne warianty deklaracji int tab[ 10 ]; #define N 10 . . . int tab[ N ]; const int N = 10; . . . int tab[ N ] C poprawne poprawne C++ poprawne poprawne niepoprawne poprawne Kwalifikator typu const może wystąpić z każdą specyfikacją typu. Zmienna z const powinna być zainicjowana ale potem nie może zmieniać wartości. Zmienna z kwalifikatorem const w języku C nie jest traktowana jako stała i nie może być wykorzystywana do określania rozmiaru tablicy. Copyright © Roman Simiński Strona : 3 Język C Podstawy i języki programowania Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — deklaracja, reprezentacja wewnętrzna Reprezentacja tablicy w pamięci operacyjnej Elementy tablicy numerowane są zawsze od 0. Zatem jeżeli N oznacza liczbę elementów tablicy, to ostatni jej element ma numer N - 1. 10 elementów #define N 10 . . . int tab[ N ]; tab 0 1 2 3 4 5 6 7 8 9 Dowoływanie się do elementów tablicy tab[ 0 ] = 1; tab[ N - 1 ] = 5; a = 2 * tab[ 3 ]; int i = 0, j = N – 1; a = tab[ i ] + tab [ j ]; W języku C i C++ nie ma żadnych wbudowanych mechanizmów zabezpieczających przed odwoływaniem się do „elementów” leżących poza zakresem indeksowym tablic! tab[ 12 ] = 10; tab 0 1 2 3 4 5 6 7 8 9 ? 10 ? 11 10 12 Obszar poza zakresem tablicy ! Copyright © Roman Simiński Strona : 4 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — deklaracja, reprezentacja wewnętrzna Tablice wolno inicjalizować na etapie deklaracji: Jeżeli inicjalizowana tablica nie posiada określonego rozmiaru, ostanie on określony na podstawie liczby elementów inicjalizujących. Jeżeli liczba wartości początkowych jest mniejsza od rozmiaru tablicy, to elementy o brakujących wartościach początkowych otrzymują wartość zero (zmienne zewnętrzne, statyczne i automatyczne). Podanie zbyt wielu wartości początkowych jest błędem. Nie ma sposobu na zainicjowanie środkowego elementu bez podania wszystkich wartości pośrednich. Typowa inicjalizacja int tab[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; Rozmiar określony liczbą wartości początkowych int dni_miesiecy[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };` Zbyt mało warości początkowych float przychody[ 12 ] = { 0, 0, 0 }; /* Za mało wartości początkowych */ Copyright © Roman Simiński Strona : 5 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Typowe operacje na tablicach Przetwarzanie tablic realizowane jest zwykle z wykorzystaniem instrukcji iteracyjnych. Do przetwarzania tablic najczęściej wykorzystuje się iterację for. #define N 10 . . . int tab[ N ]; int i; Ustawianie wartości wszystkich elementów tablicy, np. zerowanie: Wersja pierwsza: for( i = 0; i < N; i++ ) tab[ i ] = 0; Wersja druga: for( i = 0; i < N; tab[ i++ ] = 0 ) ; Ogólnie, wypełnianie pewnym wzorcem pattern: int pattern = -1; . . . for( i = 0; i < N; tab[ i++ ] = pattern ) ; Copyright © Roman Simiński Strona : 6 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Typowe operacje na tablicach, cd. ... #define N 10 . . . int tab[ N ]; int i; Wczytywanie danych ze strumienia stdin do tablicy: Wersja pierwsza: char linia[ 80 ]; . . . for( i = 0; i < N; i++ ) { printf( "\n>" ); fgets( linia, 80, stdin ); tab[ i ] = atoi( linia ); } Copyright © Roman Simiński Strona : 7 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Typowe operacje na tablicach, cd. ... #define N 10 . . . int tab[ N ]; int i; Wczytywanie danych ze strumienia stdin do tablicy: Wersja druga, z wykorzystaniem funkcji wczytaj_liczbe_int: for( i = 0; i < N; i++ ) tab[ i ] = wczytaj_liczbe_int( "\n>" ); Przykładowa realizacja funkcji wczytaj_liczbe_int: int wczytaj_liczbe_int( char komunikat[] ) { char bufor_tekstowy[ 80 ]; printf( komunikat ); fgets( bufor_tekstowy, 80, stdin ); return atoi( bufor_tekstowy ); } Copyright © Roman Simiński Strona : 8 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Typowe operacje na tablicach, cd. ... #define N 10 . . . int tab[ N ]; int i; Wyprowadzanie danych z tablicy do strumienia stdout: Wersja pierwsza: for( i = 0; i < N; i++ ) printf( "\n%d", tab[ i ] ); Wersja druga: for( i = 0; i < N; printf( "\n%d", tab[ i++ ] ) ) ; Na marginesie... Uwaga na takie konstrukcje: x = tab[ ++i ] + tab[ i ]; Copyright © Roman Simiński tab[ ++i ] = a * ++i; Strona : 9 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Typowe operacje na tablicach, cd. ... #define N 10 . . . int tab[ N ]; int i; Sumowanie liczb zapisanych w tablicy: Wersja pierwsza: int suma = 0; . . . for( i = 0; i < N; i++ ) suma = suma + tab[ i ]; Wersja druga: int suma; . . . for( i = 0, suma = 0; i < N; suma += tab[ i++ ] ) ; Copyright © Roman Simiński Strona : 10 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Typowe operacje na tablicach, cd. ... #define N 10 . . . int tab[ N ]; int i; Przykładowe „dziwactwo”: Wyznaczanie sumy co drugiego, dodatniego elementu tablicy, podzielnego przez 3: int suma; . . . for( i = 0, suma = 0; i < N; i+= 2 ) if( tab[ i ] > 0 ) if( tab[ i ] % 3 == 0 ) suma += tab[ i ]; Ponieważ wyrażenia logiczne w języku C nie są wartościowane „kompletnie”: int suma; . . . for( i = 0, suma = 0; i < N; i+= 2 ) if( tab[ i ] > 0 && tab[ i ] % 3 == 0 ) suma += tab[ i ]; Copyright © Roman Simiński Strona : 11 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Kopiowanie zawartości tablic #define N 5 int a[] = { 1, 2, 3, 4, 5 }; int b[ N ]; . . . int i; Tak w języku C nie wolno: b = a; /* Nie wolno przypisywać do siebie tablic */ Trzeba: for( i = 0; i < N; i++ ) b[ i ] = a[ i ]; Uwaga na niejednakowe rozmiary tablic #define SIZE_A #define SIZE_B 30 20 int a[ SIZE_A ]; int b[ SIZE_B ]; for( i = 0; i < SIZE_B; i++ ) b[ i ] = a[ i ]; Copyright © Roman Simiński Strona : 12 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Kopiowanie zawartości tablic, cd. ... Czasem warto napisać funkcję do kopiowania zawartości tablic: void copy_int_table( int d[], int s[], int n ) { int i = 0; for( i = 0; i < n; i++ ) d[ i ] = s[ i ]; } Lub krócej: void copy_int_table( int d[], int s[], int n ) { while( --n >= 0 ) d[ n ] = s[ n ]; } Z tymi parametrami formalnymi to coś nie gra... W języku C nazwy tablic są traktowane w specyficzny sposób. O tym już niedługo. Z tego powody wolno definiować tablicowe parametry formalne bez rozmiaru. Taki parametr przyjmuje do siebie tablicę o dowolnym rozmiarze. Tablice pozornie zachowują się tak, jakby były przekazywane przez zmienną. Copyright © Roman Simiński Strona : 13 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Tablice — przetwarzanie Kopiowanie zawartości tablic, rozwiązania alteratywne Ponieważ z definicji tablice to spójne obszary pamięci operacyjnej, można do ich kopiowania użyć funkcji memmove lub memcpy (nagłówek mem.h, zgodne z ANSI C): memmove( b, a, N * sizeof( int ) ); Lub sprytniej: memmove( b, a, N * sizeof( b[ 0 ] ) ); Alternatywnie: memcpy( b, a, N * sizeof( int ) ); Lub sprytniej: memcpy( b, a, N * sizeof( b[ 0 ] ) ); memmove( dest, src, n ); Kopiuje blok n bajtów z lokalizacji src do dest. Lokalizacje te mogą się nakładać. memcpy( dest, src, n ); Kopiuje blok n bajtów z lokalizacji src do dest. Gdy lokalizacje te się nakładają, działanie funkcji jest niezdefiniowane. Na marginesie,alternatywa dla iteracyjnego zerowania tablicy Można do tego wykorzystać funkcję memset : memset( b, 0, N * sizeof( b[ 0 ] ) ); Copyright © Roman Simiński memset( s, c, n ); Wypełnia n pierwszych bajtów obszaru s bajtem o wartości c. Strona : 14 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — koncepcja, reprezentacja wewnętrzna Łańcuchy znakowe jako tablice znaków ze znacznikiem końca Do reprezentacji łańcuchów znakowych w języku C wykorzystuje się zwykłe tablice znakowe. Tablice takie nie różnią się od innych tablic w języku C, wprowadzono jedynie kilka udogodnień czyniących łatwiejszym manipulowanie takimi tablicami. Podstawowy problem — zmienna długość łańcuchów znakowych W języku C przyjęto koncepcję łańcuchów ze znacznikiem końca (ang. null terminated strings). ”To jest napis” a to jego reprezentacja wewnętrzna: T o j e s t Fizyczna długość napisu = liczba znaków + 1 Copyright © Roman Simiński n a p i s \0 Znacznik końca napisu \0 to znak o kodzie 0 Strona : 15 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — koncepcja, reprezentacja wewnętrzna Deklarowanie i inicjowanie zmiennych łańcuchowych Tablice znakowe można inicjować w zwykły sposób, przewidziany dla tablic: #define N 80 . . . char imie[ N ] = { ’A’, ’g’, ’a’ }; char imie[] = { ’A’, ’g’, ’a’, ’\0’ }; /* \0 ??? */ /* \0 !!! */ choć można wykorzystywać wygodniejszą formę: char imie[ N ] = "Aga"; Uwaga — powyższe przypisanie wystąpić może jedynie przy definicji zmiennej! Reprezentacja wewnętrzna Literał łańcuchowy : Zmienna imie : Copyright © Roman Simiński A g a \0 0 1 2 3 A g a \0 0 1 2 3 ... 4 5 78 79 Strona : 16 Język C Podstawy i języki programowania Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — koncepcja, reprezentacja wewnętrzna Deklaracja łańcucha zainicjowanego napisem pustym char imie[ N ] = {’\0’}; char imie[ N ] = ""; Reprezentacja wewnętrzna łańcucha pustego: Zmienna imie: \0 0 ... 1 2 3 4 5 78 79 Ustawianie łańcucha pustym w po deklaracji imie[ 0 ] = ’\0’; Copyright © Roman Simiński imie = ""; /* Błąd,tak nie wolno */ Strona : 17 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Ogólny schemat przetwarzania tablic znakowych Przetwarzanie tablic polega zwykle na „przemaszerowaniu” zmienna indeksową po tablicy, dopóki nie ma końca napisu oznaczanego znakiem ’\0’: int i; char s[ N ]; . . . for( i = 0; s[ i ] != ’\0’; i++ ) < tu jakieś operacje na każdym znaku s[ i ] > Wyprowadzanie napisu do stdout znak po znaku: int i; char s[ N ]; . . . for( i = 0; s[ i ] != ’\0’; i++ ) putchar( s[ i ] ); Albo w krótszej postaci: int i; char s[ N ]; . . . for( i = 0; s[ i ] != ’\0’; putchar( s[ i++ ] ) ) ; Copyright © Roman Simiński Strona : 18 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Przetwarzanie z wykorzystaniem funkcji bibliotecznych — string.h Do manipulowania tablicami znakowymi opracowano szereg funkcji bibliotecznych (plik nagłówkowy string.h),... większość z nich można łatwo napisać samemu! Funkcja strlen — wyznaczanie długości łańucha Rezultatem funkcji strlen jest liczba znaków napisu, przekazanego tej funkcji parametrem. #define N 80 char napis[ N ] = "Język C"; . . . printf( "Liczba znaków w łańcuchu:%s wynosi:%d", napis, strlen( napis ) ); Liczba znaków w łańcuchu:Język C wynosi:7 Alternatywny schemat przetwarzania napisów (z wykorzystaniem strlen): int i, len; Uwaga — nigdy tak i < strlen( s ) char s[ N ]; . . . for( i = 0, len = strlen( s ) ; i < len; putchar( s[ i++ ] ) ) ; Copyright © Roman Simiński Strona : 19 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Funkcja strlen — przykładowe realizacje Iteracja while int strlen( char s[] ) { int len = 0; while( s[ len ] != '\0' ) len++; return len; } Iteracja for int strlen( char s[] ) { int len; for( len = 0; s[ len ] != '\0'; len++ ) ; return len; } Copyright © Roman Simiński Strona : 20 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Funkcje strupr i strlwr — przykładowe realizacje Konwersja - małe litery na duże: strupr, duże litery na małe: strlwr. char a[] = "ALA"; char b[] = "ala"; strlwr( a ); /* Po wywołaniu strlwr zmienna a zawiera napis "ala" strupr( b ); /* Po wywołaniu strupr zmienna a zawiera napis "ALA" */ */ Funkcja strupr void strupr( char s[] ) { int i; for( i = 0; s[ i ] != '\0'; i++ ) s[ i ] = toupper( s[ i ] ); } Konwersja elementu tablicy, toupper zamienia znak będący parametrem na literę dużą, o ile był literą małą. Funkcja strlwr void strlwr( char s[] ) { int i; for( i = 0; s[ i ] != '\0'; i++ ) s[ i ] = tolower( s[ i ] ); } Copyright © Roman Simiński Konwersja elementu tablicy, tolower zamienia znak będący parametrem na literę małą, o ile był literą dużą. Strona : 21 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Funkcja strcpy — koncepcja kopiowania napisów Pamiętamy, że w języku nie można kopiować zawartości tablic wykorzystując operator przypisania. char s1[ 80 ] = "Język C"; char s2[ 20 ]; s2 = s1; /* Tak nie wolno !!! */ Do kopiowania zawartości tablic znakowych używamy funkcji strcpy: strcpy( s2, s1 ); Funkcja strcpy kopiuje zawartość tablicy znakowej s1 do tablicy s2. Kopiowaniu podlegają wszystkie znaki łańcucha s1 (aż do \0), zakłada się, że tablica s2 ma rozmiar wystarczający na pomieszczenie kopiowanych znaków. Funkcja strcpy służy również do kopiowania literałów łańcuchowych: strcpy( s1, "Programowanie " ); strcpy( s2, "w języku C" ); Copyright © Roman Simiński Strona : 22 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Funkcja strcpy — przykładowe realizacje Funkcja strcpy — wersja pierwsza, iteracja for char s1[ 80 ] = "Język C"; char s2[ 20 ]; . . . strcpy( s2, s1 ); i++ s d s1 s2 . . J ę z y k 0 1 2 3 4 J ę z y k 0 1 2 3 4 void strcpy( char d[], char s[] ) { int i; for( i = 0; s[ i ] != '\0'; i++ ) d[ i ] = s[ i ]; d[ i ] = '\0'; } Copyright © Roman Simiński . C 5 ... 79 6 C 5 \0 6 \0 ... 19 Ta wersja funkcji strcpy przepisuje znacznik końca napisu z tablicy s do d, jednak dzieje się to poza iteracją, tuż po jej zakończeniu: d[ i ] = '\0'; Strona : 23 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Funkcja strcpy — przykładowe realizacje, cd. ... Funkcja strcpy — wersja druga, iteracja for void strcpy( char d[], char s[] ) { int i = 0; while( ( d[ i ] = s[ i ] ) != '\0' ) i++; } Jak to działa? W języku C operator przypisania jest lewostronnie łączny. Pozwala to na pisanie następujących konstrukcji, np.: d[ 0 ] = d[ 1 ] = d[ 2 ] = 0; Konstrukcja: ( d[ i ] = s[ i ] ) != '\0' przypisuje i-ty element tablicy s do i-tego elementu tablicy d. Przypisana wartość jest następnie porównywana (operator !=) ze znacznikiem końca napisu '\0'. Ta wersja funkcji strcpy przepisuje znacznik końca napisu z tablicy s do d w iteracji while. Copyright © Roman Simiński Strona : 24 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Co się stanie, gdy tablica docelowa jest za krótka? void main() { char s1[ 5 ] = "AAAA"; char c1 = 'A'; char c2 = 'B'; char s2[ 5 ] = "BBBB"; strcpy( s2, "XXXXXXXXXXXXXXXXXXXX" ); printf( "\ns1 : %s\nc1 : %c\nc2 : %c\ns2 : %s", s1, c1, c2, s2 ); } Gdzie oryginalna zawartość tablicy s1? Co się stało ze zmienną c2? Dlaczego zmienna c1 jest OK? Nigdy nie należy zakładać, że „się uda”, czyli że tablica docelowa jest wystarczająco długa. Należy szacować, przewidywać, jeszcze raz przewidywać — programować defensywnie. Copyright © Roman Simiński Strona : 25 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Funkcja strcat — przykładowa realizacja Funkcja strcat dołącza zawartość tablicy znakowej s1 do tablicy s2. Kopiowaniu podlegają wszystkie znaki łańcucha s1 (aż do \0), zakłada się, że tablica s2 ma rozmiar wystarczający na pomieszczenie kopiowanych znaków. strcpy( s1, "Programowanie " ); strcpy( s2, "w języku C" ); strcat( s1, s2 ); puts( s1 ); Programowanie w języku C Jak to działa? void strcat( char d[], char s[] ) { int i = 0, j = 0; Znajdź znacznik końca napisu docelowego, zapamiętaj jego pozycje w zmiennej i. while( d[ i ] != ’\0’ ) i++; while( ( d[ i++ ] = s[ j++ ] ) != ’\0’ ) ; } Copyright © Roman Simiński Przepisz elementy tablicy s do tablicy d. Maszeruj zmienną j od początku tablicy s, zmienną i od pozycji znalezionego wcześniej znacznika końca napisu. Strona : 26 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Jak nie dopuszczać do „przepełnienia bufora”? Biblioteka funkcji operujących na tablicach znaków zawiera funkcje wykonujące operacje analogiczne do przedstawionych uprzednio, pozwalające na kontrolę liczby znaków biorących udział np. w kopiowaniu. Są to np. funkcje: strncpy, strncat, strnset. #define N 10 #define M 80 char s1[ N ]; char s2[ M ] = "Język C jest świetny lecz pełen pułapek"; strncpy( s1, s2, N - 1 ); s1[ N - 1 ] = '\0'; strncpy( s1, s2, sizeof( s1 ) - 1 ); s1[ sizeof( s1 ) - 1 ] = '\0'; puts( s1 ); puts( s1 ); Funkcja strncpy nie zawsze przekopiuje ’\0’! Ciekawostka Często rezultatem funkcji operujących na tablicach są one same. Rezultatem funkcji strncpy jest tablica będąca pierwszym parametrem a więc, w naszym przypadku, s1. strncpy( s1, s2, N - 1 ) [ N - 1 ] = '\0'; s1 Copyright © Roman Simiński Skrócona wersja kopiowania i dopisywania znacznika końca napisu Strona : 27 Podstawy i języki programowania Język C Tablice — koncepcja, reprezentacja, przetwarzanie Łańcuchy znakowe — typowe operacje Funkcja strncpy — przykładowa, bezpieczniejsza realizacja Wersja z iteracją while void strncpy_while( char d[], char s[], int n ) { int i = 0; while( ( d[ i ] = s[ i ] ) != '\0' && i < n ) i++; while( i <= n ) d[ i++ ] = '\0'; } Wersja z iteracją for void strncpy_for( char d[], char s[], int n ) { int i = 0; for( ; ( d[ i ] = s[ i ] ) != '\0' && i < n ; i++ ) ; for( ; i <= n ; d[ i++ ] = '\0' ) ; } Copyright © Roman Simiński Strona : 28