C/Tablice - więcej: Różnice pomiędzy wersjami

Z Wikibooks, biblioteki wolnych podręczników.
< C
Usunięta treść Dodana treść
Nie podano opisu zmian
Linia 1: Linia 1:
== Deklaracja tablic ==
== Deklaracja tablic ==
Deklarując [[C/Tablice|tablicę]] i podając jej wartości początkowe, możemy podać tylko część wartości (mniej niż rozmiar tablicy), pozostałe zainicjowane zostaną zerami. Ponadto, możemy użyć indeksów aby przekazać, które wartości tablicy inicjujemy. Może to się wydać dziwne, ale po ostatnim elemencie tablicy może występować przecinek.
Deklarując [[C/Tablice|tablicę]] i podając jej wartości początkowe, możemy podać tylko część wartości (mniej niż rozmiar tablicy), pozostałe zainicjowane zostaną zerami. Ponadto, możemy użyć indeksów aby przekazać, które wartości tablicy inicjujemy. Może to się wydać dziwne, ale po ostatnim elemencie tablicy może występować przecinek.
<source lang="c">
<syntaxhighlight lang="c">
int tablica1[20] = {1,};
int tablica1[20] = {1,};
int tablica2[20] = {0,1,[4]4,[7]=7,8,9,}; /* {0,1,0,0,4,0,0,7,8,9,0,0,0,0,0,0,0,0,0,0) */
int tablica2[20] = {0,1,[4]4,[7]=7,8,9,}; /* {0,1,0,0,4,0,0,7,8,9,0,0,0,0,0,0,0,0,0,0) */
</syntaxhighlight>
</source>


Możemy to stosować również przy deklaracji tablicach bez podanego rozmiaru:
Możemy to stosować również przy deklaracji tablicach bez podanego rozmiaru:
<source lang="c">
<syntaxhighlight lang="c">
int tablica[] = {0, [3]3, 4}; // tablica 5-elementowa
int tablica[] = {0, [3]3, 4}; // tablica 5-elementowa
</syntaxhighlight>
</source>


Jak i przy deklaracji tablic wielowymiarowych:
Jak i przy deklaracji tablic wielowymiarowych:
<source lang="c">
<syntaxhighlight lang="c">
float macierz[4][5] = {
float macierz[4][5] = {
{ 1.6, [2]2.4, 5.6 }, /* pierwszy wiersz */
{ 1.6, [2]2.4, 5.6 }, /* pierwszy wiersz */
Linia 19: Linia 19:
{ 8.8, 7.5, } /* piąty wiersz */
{ 8.8, 7.5, } /* piąty wiersz */
};
};
</syntaxhighlight>
</source>


== Definiowanie rozmiaru tablicy ==
== Definiowanie rozmiaru tablicy ==
Przyjrzyjmy się nadaniu rozmiaru tablicy przez użycie stałej definiowanej
Przyjrzyjmy się nadaniu rozmiaru tablicy przez użycie stałej definiowanej


<source lang="c">
<syntaxhighlight lang="c">
#define ROZMIAR 3
#define ROZMIAR 3
int main()
int main()
Linia 30: Linia 30:
int tab[ROZMIAR] = {3,6,8};
int tab[ROZMIAR] = {3,6,8};
}
}
</syntaxhighlight>
</source>


{{infobox|W pierwotnym standardzie języka C rozmiar tablicy nie mógł być określany przez zmienną lub nawet stałą zadeklarowaną przy użyciu [[C/Zmienne#Stałe|słowa kluczowego const]]. Dopiero w późniejszej wersji standardu (tzw. C99) dopuszczono taką możliwość. Dlatego do deklarowania rozmiaru tablic często używa się dyrektywy preprocesora [[C/Preprocesor##define|#define]]. Powinni na to zwrócić uwagę zwłaszcza [[C++/Różnice między C a C++|programiści C++]], gdyż tam zawsze możliwe były oba sposoby.}}
{{infobox|W pierwotnym standardzie języka C rozmiar tablicy nie mógł być określany przez zmienną lub nawet stałą zadeklarowaną przy użyciu [[C/Zmienne#Stałe|słowa kluczowego const]]. Dopiero w późniejszej wersji standardu (tzw. C99) dopuszczono taką możliwość. Dlatego do deklarowania rozmiaru tablic często używa się dyrektywy preprocesora [[C/Preprocesor##define|#define]]. Powinni na to zwrócić uwagę zwłaszcza [[C++/Różnice między C a C++|programiści C++]], gdyż tam zawsze możliwe były oba sposoby.}}


Innym sposobem jest użycie operatora <tt>sizeof</tt> do poznania wielkości tablicy. Poniższy kod robi to samo co przedstawiony:
Innym sposobem jest użycie operatora <tt>sizeof</tt> do poznania wielkości tablicy. Poniższy kod robi to samo co przedstawiony:
<source lang="c">
<syntaxhighlight lang="c">
#include <stdio.h>
#include <stdio.h>
int main()
int main()
Linia 48: Linia 48:
return 0;
return 0;
}
}
</syntaxhighlight>
</source>


Powyżej <tt>sizeof tab</tt> zwraca cały rozmiar pamięciowy tablicy, natomiast <tt>sizeof *tab</tt> poda nam jaki jest rozmiar typu <tt>int</tt> (ponieważ takiego typu jest element tablicy, *tab). Dzieląc rozmiar pamięciowy tablicy przez rozmiar pojedynczego elementu uzyskujemy ilość elementów. (Np. przy rozmiarze 44B oraz rozmiarze sizeof(int) równym 4 otrzymujemy, że tablica zawiera 11 elementów.)
Powyżej <tt>sizeof tab</tt> zwraca cały rozmiar pamięciowy tablicy, natomiast <tt>sizeof *tab</tt> poda nam jaki jest rozmiar typu <tt>int</tt> (ponieważ takiego typu jest element tablicy, *tab). Dzieląc rozmiar pamięciowy tablicy przez rozmiar pojedynczego elementu uzyskujemy ilość elementów. (Np. przy rozmiarze 44B oraz rozmiarze sizeof(int) równym 4 otrzymujemy, że tablica zawiera 11 elementów.)
Linia 59: Linia 59:
== Ciekawostki ==
== Ciekawostki ==
W pierwszej edycji konkursu [[w:IOCCC|IOCCC]] zwyciężył program napisany w C, który wyglądał dość nietypowo:
W pierwszej edycji konkursu [[w:IOCCC|IOCCC]] zwyciężył program napisany w C, który wyglądał dość nietypowo:
<source lang="c">
<syntaxhighlight lang="c">
short main[] = {
short main[] = {
277, 04735, -4129, 25, 0, 477, 1019, 0xbef, 0, 12800,
277, 04735, -4129, 25, 0, 477, 1019, 0xbef, 0, 12800,
Linia 70: Linia 70:
'p', 072163, 'r', 29303, 29801, 'e'
'p', 072163, 'r', 29303, 29801, 'e'
};
};
</syntaxhighlight>
</source>
Co ciekawe - program ten bez przeszkód wykonywał się na komputerach [[w:en:VAX|VAX]]-11 oraz [[w:PDP|PDP]]-11. Cały program to po prostu tablica z zawartym wewnątrz kodem maszynowym! Tak naprawdę jest to wykorzystanie pewnych właściwości programu, który ostatecznie produkuje kod maszynowy. Linker (to o nim mowa) nie rozróżnia na dobrą sprawę nazw funkcji od nazw zmiennych, więc bez problemu ustawił punkt wejścia programu na tablicę wartości, w których zapisany był kod maszynowy. Tak przygotowany program został bez problemu wykonany przez komputer.
Co ciekawe - program ten bez przeszkód wykonywał się na komputerach [[w:en:VAX|VAX]]-11 oraz [[w:PDP|PDP]]-11. Cały program to po prostu tablica z zawartym wewnątrz kodem maszynowym! Tak naprawdę jest to wykorzystanie pewnych właściwości programu, który ostatecznie produkuje kod maszynowy. Linker (to o nim mowa) nie rozróżnia na dobrą sprawę nazw funkcji od nazw zmiennych, więc bez problemu ustawił punkt wejścia programu na tablicę wartości, w których zapisany był kod maszynowy. Tak przygotowany program został bez problemu wykonany przez komputer.


Linia 90: Linia 90:




<source lang=c>
<syntaxhighlight lang=c>




Linia 168: Linia 168:


</syntaxhighlight>
</source>




Linia 174: Linia 174:
Wynik :
Wynik :


<source lang=bash>
<syntaxhighlight lang=bash>




Linia 190: Linia 190:
i = 2 b[i] = 1.350000
i = 2 b[i] = 1.350000


</syntaxhighlight>
</source>





Wersja z 19:23, 9 lut 2021

Deklaracja tablic

Deklarując tablicę i podając jej wartości początkowe, możemy podać tylko część wartości (mniej niż rozmiar tablicy), pozostałe zainicjowane zostaną zerami. Ponadto, możemy użyć indeksów aby przekazać, które wartości tablicy inicjujemy. Może to się wydać dziwne, ale po ostatnim elemencie tablicy może występować przecinek.

 int tablica1[20] = {1,};
 int tablica2[20] = {0,1,[4]4,[7]=7,8,9,}; /* {0,1,0,0,4,0,0,7,8,9,0,0,0,0,0,0,0,0,0,0) */

Możemy to stosować również przy deklaracji tablicach bez podanego rozmiaru:

int tablica[] = {0, [3]3, 4};  // tablica 5-elementowa

Jak i przy deklaracji tablic wielowymiarowych:

float macierz[4][5] = {
 { 1.6, [2]2.4, 5.6 },    /* pierwszy wiersz */
 [2]{ [1]7.5, [3]=8.6 },    /* trzeci wiersz */
 {},    /* czwarty wiersz */
 { 8.8, 7.5, }    /* piąty wiersz */
};

Definiowanie rozmiaru tablicy

Przyjrzyjmy się nadaniu rozmiaru tablicy przez użycie stałej definiowanej

#define ROZMIAR 3
int main()
{
   int tab[ROZMIAR] = {3,6,8};
}

Innym sposobem jest użycie operatora sizeof do poznania wielkości tablicy. Poniższy kod robi to samo co przedstawiony:

 #include <stdio.h>
 int main()
 {
   int tab[3] = {3,6,8};
   int i;
   printf ("Druk tablicy tab:\n");
 
   for (i=0; i<(sizeof tab / sizeof *tab); ++i) {
     printf ("Element numer %d = %d\n", i, tab[i]);
   }
   return 0;
 }

Powyżej sizeof tab zwraca cały rozmiar pamięciowy tablicy, natomiast sizeof *tab poda nam jaki jest rozmiar typu int (ponieważ takiego typu jest element tablicy, *tab). Dzieląc rozmiar pamięciowy tablicy przez rozmiar pojedynczego elementu uzyskujemy ilość elementów. (Np. przy rozmiarze 44B oraz rozmiarze sizeof(int) równym 4 otrzymujemy, że tablica zawiera 11 elementów.)

Należy pamiętać, że sposób działa tylko dla tablic, a nie wskaźników (mimo że wskaźniki traktujemy w pewnym stopniu podobnie jak tablice).

Pobieranie wartości

Przy odwoływaniu się do konkretnej komórki tablicy, używanym indeksem powinna być liczba, choć istnieje możliwość indeksowania za pomocą np. pojedynczych znaków ('a','b', itp.), jednak w języku C dokonuje się wewnętrzna konwersja takich znaków na liczby im odpowiadające, zatem tablica indeksowana znakami byłaby niepraktyczna i musiałaby mieć odpowiednio większy rozmiar (numerem ASCII dla 'a' jest 97).

Ciekawostki

W pierwszej edycji konkursu IOCCC zwyciężył program napisany w C, który wyglądał dość nietypowo:

 short main[] = {
   277, 04735, -4129, 25, 0, 477, 1019, 0xbef, 0, 12800,
   -113, 21119, 0x52d7, -1006, -7151, 0, 0x4bc, 020004,
   14880, 10541, 2056, 04010, 4548, 3044, -6716, 0x9,
   4407, 6, 5568, 1, -30460, 0, 0x9, 5570, 512, -30419,
   0x7e82, 0760, 6, 0, 4, 02400, 15, 0, 4, 1280, 4, 0,
   4, 0, 0, 0, 0x8, 0, 4, 0, ',', 0, 12, 0, 4, 0, '#',
   0, 020, 0, 4, 0, 30, 0, 026, 0, 0x6176, 120, 25712,
   'p', 072163, 'r', 29303, 29801, 'e'
 };

Co ciekawe - program ten bez przeszkód wykonywał się na komputerach VAX-11 oraz PDP-11. Cały program to po prostu tablica z zawartym wewnątrz kodem maszynowym! Tak naprawdę jest to wykorzystanie pewnych właściwości programu, który ostatecznie produkuje kod maszynowy. Linker (to o nim mowa) nie rozróżnia na dobrą sprawę nazw funkcji od nazw zmiennych, więc bez problemu ustawił punkt wejścia programu na tablicę wartości, w których zapisany był kod maszynowy. Tak przygotowany program został bez problemu wykonany przez komputer.


Zapisywanie tablic do pliku

  • tekstowego
  • binarnego

binarnego

Ten sposób pozwalan na:

  • szybki dostęþ do duzych plików[1]

Funkcje


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

int main ()
{
  FILE * pbFile;
  
  char * fName  = "a1.dat";
  
  // input static array
  double a[] = { 1.333333333333333 , 1.44444444444444444 , 1.5555555555555555, 1.66666666666666666666666};
  long ALength; // number of array's elements = ENumber
  size_t ASize; // size of array in bytes
  size_t ESize; // size of array's element in bytes
  int i;
  
  // for output array (dynamic arrray read from binary file )
  double * b; // 
  size_t result;
  size_t FSize;

  
  
  
  // test input
  ASize = sizeof(a); // 
  ESize = sizeof(a[0]);
  ALength = ASize/ESize; // number of elements  = Length of array
  
  printf("array has %ld elements of %zu bytes so the array size = %zu bytes\n", ALength, ESize, ASize ); 
  for (i=0; i< ALength; i++)
  	printf("i = %d \t a[i] = %f\n",i, a[i]);
  
  
  // write to the binary file 
  pbFile = fopen (fName, "wb");
  fwrite (a , ESize, ALength, pbFile);
  fclose (pbFile);
  printf("array have been saved to the  %s file\n", fName);
  
  // open binary file 
  pbFile = fopen( fName , "rb" );
  if (pbFile==NULL) {fputs ("File open error",stderr); return 1;}
  
   // obtain file size:
  fseek (pbFile , 0 , SEEK_END);
  FSize = ftell (pbFile);
  rewind (pbFile);
  printf("file size = %zu\n", FSize);

  // allocate memory to contain the whole file:
  b = (double *) malloc (ESize*ALength);
  if (b == NULL) {fputs ("Memory error",stderr); return 2;}

  // copy the file into the buffer:
  result = fread (b,ESize,ALength,pbFile);
  if (result != ALength) {printf("Reading error: result = %zu != %ld \n",result, ALength); return 3;}

  /* the whole file is now loaded in the memory buffer. */
  
  // print the array 
  printf("array has %ld elements of %zu bytes so the array size = %zu bytes\n", ALength, ESize, ASize ); 
  for (i=0; i< ALength; i++)
  	printf("i = %d \t b[i] = %f\n",i, b[i]);
  
  
  // terminate
  fclose (pbFile);
  free (b);
  
  
  return 0;
}


Wynik :

gcc a.c -Wall
./a.out
array has 3 elements of 8 bytes so the array size = 24 bytes
i = 0 	 a[i] = 1.330000
i = 1 	 a[i] = 1.340000
i = 2 	 a[i] = 1.350000
array have been saved to the  a.dat file
file size = 24
array has 3 elements of 8 bytes so the array size = 24 bytes
i = 0 	 b[i] = 1.330000
i = 1 	 b[i] = 1.340000
i = 2 	 b[i] = 1.350000



W przypadku pliku utworzonego na innym komputerze/programi trzeba sprawdzić

  • kolejność bajtów ( ang. endianess)[4]

biblioteki

Źródła

  1. Fast Reading and Writing of Binary Data in C by David S. Smith,
  2. cplusplus fwrite
  3. cplusplus fread
  4. Reading binary files from PCs on "other endian" machines Written by Paul Bourke March 1991