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