Tak!
#include <stdio.h>
#include <stdlib.h>
int main()
{
int tab[3][2] = {{2,-3},{5,4},{8,7}};
//wskaznik do tablicy dwóch wartosci int
//operator [] ma wyzszy priorytet niz *
int (*wsk)[2];
wsk=tab;
printf("%d %p %p\n",**wsk,*wsk,wsk);
printf("%d %p %p\n",**(wsk+1),*(wsk+1),wsk+1);
printf("%d %p\n",*(wsk[0]),wsk[0]);
printf("%d %p\n",*(wsk[1]),wsk[1]);
printf("%d %p\n",*(wsk[2]),wsk[2]);
printf("%d %p\n",*(wsk[1]+1),wsk[1]+1);
printf("%d %p\n",*(*wsk+1),*wsk+1);
printf("%d\n",*wsk[1]);
printf("%d\n",**wsk+1);
printf("%d\n",wsk[2][1]);
printf("%d\n",*(*(wsk+2)+1));
return 0;
}
#include <stdlib.h>
#include <stdio.h>
int main()
{
//tablica dwoch wskazników do int
int *wsk[2]= {
(int[]) {3,4,5},
(int[]) {-2,3,-4},
};
printf("%d %p\n",wsk[0][0],&wsk[0][0]);
printf("%d %p\n",wsk[0][1],&wsk[0][1]);
printf("%d %p\n",wsk[0][2],&wsk[0][2]);
printf("%d %p\n",wsk[0][3],&wsk[0][3]);
printf("%d %p\n",wsk[1][0],&wsk[1][0]);
printf("%d %p\n",*(*(wsk+1)+2),*(wsk+1)+2);
return 0;
}
Tablica postrzępiona jest to taka dwuwymiarowa tablica, która posiada różną liczbę kolumn w każdym rzędzie.
int *** alokuj(int n, int m, int k)
{
int *** tab = malloc(n*sizeof(int **));
for(int i=0;i<n;i++)
{
tab[i] = malloc(m*sizeof(int*));
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
tab[i][j] = malloc(k*sizeof(int));
}
}
return tab;
}
void zwolnij(int *** tab, int n, int m, int k)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
free(tab[i][j]);
}
}
for(int i=0;i<n;i++)
{
free(tab[i]);
}
free(tab);
}
int main()
{
int *** tab = alokuj(2,3,4);
zwolnij(tab,2,3,4);
return 0;
}
Struktury to specjalny typ danych mogący przechowywać wiele wartości w jednej zmiennej. Od tablic jednakże różni się tym, iż te wartości mogą być różnych typów.
Deklaracja struktury:
Deklaracja zmiennej strukturalnej:
Dostęp do pól - “kropka” - operator wyboru składnika:
#include <stdio.h>
#include <stdlib.h>
struct Struktura {
int pole1;
int pole2;
char pole3;
};
int main()
{
struct Struktura zmiennaS =
{ .pole1=60, .pole2=0.2, .pole3='a'};
printf("%d\n",zmiennaS);
printf("%p\n",&zmiennaS);
printf("%p\n",&zmiennaS.pole1);
printf("%p\n",&zmiennaS.pole2);
printf("%p\n",&zmiennaS.pole3);
}
Co znaczy nazwa struktury?
#include <stdio.h>
#include <stdlib.h>
struct Test{
int p1;
char p2;
//double p3; //porównac po odkomentowaniu poczatku linijki
};
int main()
{
struct Test a={22,'w'};
printf("%d\n",a); //unexptected
printf("%p\n",&a); // adres struktury/pierwszego pola
printf("%p\n",&a.p1); //adres pierwszego pola
//printf("%p\n",(&a).p1); //blad kompilacji
printf("%p\n",&a.p2); //adres drugiego pola
//printf("%d\n",*a); //brak kompilacji
printf("%d\n",*(&a)); //unexptected
printf("%d\n",a.p1); //wartosc pierwszego pola
printf("%c\n",a.p2); //wartosc drugiego pola pola
return 0;
}
Parę zasad dla GCC:
Pola są wyrównane do swojego naturalnego granicznika: Typy danych o wielkości 1 bajta (np. char
) są wyrównane do granicy 1 bajta, typy danych o wielkości 2 bajty (np. short
) są wyrównane do granicy 2 bajtów, a typy danych o wielkości 4 bajty (np. int
, float
) są wyrównane do granicy 4 bajtów, itd. Oznacza to, że adres w pamięci dla danego pola jest zawsze podzielny przez wielkość tego pola.
Całkowity rozmiar struktury jest wyrównany do największego granicznika używanego przez jakiekolwiek z jej pól: Na przykład, jeśli struktura ma największe pole typu int
, to cały rozmiar struktury będzie wielokrotnością wielkości int
, czyli 4 bajtów.
Kolejność pól ma znaczenie: Pisanie pól w strukturze od największego do najmniejszego rozmiaru może zminimalizować ilość paddingu.
#include <stdio.h>
#include <stdlib.h>
// Definicja struktury
struct Punkt2D {
float x;
float y;
};
int main() {
// Alokacja pamięci dla struktury Punkt2D
struct Punkt2D *punkt = (struct Punkt2D *)malloc(sizeof(struct Punkt2D));
// Przypisanie wartości do pól struktury poprzez wskaźnik
punkt->x = 3.0;
punkt->y = 4.0;
printf("Punkt przed przesunieciem: (%.1f, %.1f)\n", punkt->x, punkt->y);
// Przesunięcie punktu o wektor (2.0, 3.0)
punkt->x += 2.0;
punkt->y += 3.0;
printf("Punkt po przesunieciu: (%.1f, %.1f)\n", punkt->x, punkt->y);
// Zwolnienie zaalokowanej pamięci
free(punkt);
return 0;
}
#include <stdio.h>
struct ksiazka {
char tytul[50];
char autor[50];
int liczba_stron;
float ocena;
};
void wyswietlKsiazki(struct ksiazka* tablica, int rozmiar) {
for (int i = 0; i < rozmiar; i++) {
printf("Tytul: %s\n", tablica[i].tytul);
printf("Autor: %s\n", tablica[i].autor);
printf("Liczba stron: %d\n", tablica[i].liczba_stron);
printf("Ocena: %.2f\n", tablica[i].ocena);
printf("\n");
}
}
int main() {
struct ksiazka biblioteka[2] = {
{"Wiedzmin", "Andrzej Sapkowski", 320, 8.7},
{"1984", "George Orwell", 328, 8.5}
};
wyswietlKsiazki(biblioteka, 2);
return 0;
}
#include <stdio.h>
struct ksiazka {
char tytul[50];
char autor[50];
int liczba_stron;
float ocena;
};
struct ksiazka znajdzKsiazkeZNajwiekszaLiczbaStron(struct ksiazka* tablica, int rozmiar) {
struct ksiazka najwieksza = tablica[0];
for (int i = 1; i < rozmiar; i++) {
if (tablica[i].liczba_stron > najwieksza.liczba_stron) {
najwieksza = tablica[i];
}
}
return najwieksza;
}
int main() {
struct ksiazka biblioteka[3] = {
{"Wiedzmin", "Andrzej Sapkowski", 320, 8.7},
{"1984", "George Orwell", 328, 8.5},
{"War and Peace", "Leo Tolstoy", 1225, 9.0}
};
struct ksiazka najwieksza = znajdzKsiazkeZNajwiekszaLiczbaStron(biblioteka, 3);
printf("Ksiazka z najwieksza liczba stron to: %s\n", najwieksza.tytul);
printf("Liczba stron: %d\n", najwieksza.liczba_stron);
return 0;
}
typedef
typedef
to słowo kluczowe w języku C, które pozwala na definiowanie aliasów dla typów danych. W kontekście struktur, typedef
jest często używane w celu uproszczenia deklaracji zmiennych strukturalnych i funkcji.
Wariant 1 - Użycie typedef
podczas definiowania struktury:
Wariant 2 - Użycie typedef
po definiowaniu struktury:
Wariant 3 - Użycie typedef
w kombinacji ze wskaźnikami na strukturę:
Wariant 4 - Użycie typedef
w funkcjach przyjmujących struktury jako argumenty:
#include <stdio.h>
struct Punkt2D {
float x;
float y;
};
void przesun_punkt(struct Punkt2D *p, float dx, float dy) {
p->x += dx;
p->y += dy;
}
int main() {
struct Punkt2D punkt = {3.0, 4.0};
printf("Punkt przed przesunieciem: (%.1f, %.1f)\n", punkt.x, punkt.y);
przesun_punkt(&punkt, 2.0, 3.0); // przekazanie struktury przez wskaźnik
printf("Punkt po przesunieciu: (%.1f, %.1f)\n", punkt.x, punkt.y);
return 0;
}
Przykład zwracania struktury jako zwykłej zmiennej:
#include <stdio.h>
struct Point {
int x;
int y;
};
struct Point add_points(struct Point p1, struct Point p2) {
struct Point result;
result.x = p1.x + p2.x;
result.y = p1.y + p2.y;
return result;
}
int main() {
struct Point p1 = {1, 2};
struct Point p2 = {3, 4};
struct Point sum = add_points(p1, p2);
printf("sum: (%d, %d)\n", sum.x, sum.y);
return 0;
}
Przykład zwracania struktury przez wskaźnik przekazany jako argument:
#include <stdio.h>
struct Point {
int x;
int y;
};
void add_points(struct Point p1, struct Point p2, struct Point *result) {
result->x = p1.x + p2.x;
result->y = p1.y + p2.y;
}
int main() {
struct Point p1 = {1, 2};
struct Point p2 = {3, 4};
struct Point sum;
add_points(p1, p2, &sum);
printf("sum: (%d, %d)\n", sum.x, sum.y);
return 0;
}
Przykład zwracania struktury przez wskaźnik przekazany (bezpośrednio):
#include <stdio.h>
#include <stdlib.h>
struct Person {
char *name;
int age;
};
struct Person *create_person(char *name, int age) {
struct Person *new_person = malloc(sizeof(struct Person));
new_person->name = name;
new_person->age = age;
return new_person;
}
int main() {
struct Person *person1 = create_person("John Doe", 30);
printf("Name: %s, Age: %d\n", person1->name, person1->age);
free(person1);
return 0;
}
Unia (ang. union) jest typem, który pozwala przechowywać różne rodzaje danych w tym samym obszarze pamięci (jednak nie równocześnie).
#include <stdio.h>
#include <stdlib.h>
union Liczba
{
int a;
float b;
};
struct Dane
{
int tp;
union Liczba zaw;
};
struct Dane wczytaj()
{
struct Dane temp;
printf("Jesli chcesz wpisac liczbe calk to wpisz 0,a jesli wymierna to wpisz 1\n");
scanf("%d", &temp.tp);
if (temp.tp ==0)
{
scanf("%d", &temp.zaw.a);
}
else
{
scanf("%f", &temp.zaw.b);
}
return temp;
};
void wyswietl(struct Dane arg)
{
if (arg.tp ==0)
{
printf("%d\n", arg.zaw.a);
}
else
{
printf("%f\n", arg.zaw.b);
}
}
int main()
{
union Liczba zm;
zm.a =5;
printf("%d\n", zm.a);
printf("%f\n", zm.b);
zm.b=3.4;
printf("%d\n", zm.a);
printf("%f\n", zm.b);
struct Dane dane1;
dane1= wczytaj();
wyswietl(dane1);
return 0;
}
Służy do tworzenia zmiennych, które mogą przyjmować tylko pewne z góry ustalone wartości:
#include <stdio.h>
#include <string.h>
struct Laptop {
char model[30];
float cena;
};
struct Laptop initLaptop(char* model, float cena) {
struct Laptop nowyLaptop;
strncpy(nowyLaptop.model, model, sizeof(nowyLaptop.model) - 1);
nowyLaptop.model[sizeof(nowyLaptop.model) - 1] = '\0';
nowyLaptop.cena = cena;
return nowyLaptop;
}
void pokazLaptop(struct Laptop laptop) {
printf("Model: %s\n", laptop.model);
printf("Cena: %.2f\n", laptop.cena);
}
void zmniejszCene(struct Laptop* laptop) {
laptop->cena *= 0.95;
}
int main() {
struct Laptop mojLaptop = initLaptop("Dell XPS 15", 5000.0);
pokazLaptop(mojLaptop);
zmniejszCene(&mojLaptop);
printf("Po obnizce ceny:\n");
pokazLaptop(mojLaptop);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Ksiazka {
char tytul[50];
int liczba_stron;
} Ksiazka;
Ksiazka* initKsiazka(const char *tytul, int liczba_stron) {
if(strlen(tytul) < 5 || liczba_stron <= 50)
return NULL;
Ksiazka* nowa_ksiazka = (Ksiazka*)malloc(sizeof(Ksiazka));
strcpy(nowa_ksiazka->tytul, tytul);
nowa_ksiazka->liczba_stron = liczba_stron;
return nowa_ksiazka;
}
void pokazKsiazka(Ksiazka ksiazka) {
printf("Tytul: %s, Liczba stron: %d\n", ksiazka.tytul, ksiazka.liczba_stron);
}
void dodajStrony(Ksiazka *ksiazka) {
ksiazka->liczba_stron += 10;
}
int main() {
Ksiazka* ksiazka1 = initKsiazka("Wojna i pokoj", 1200);
if(ksiazka1 != NULL) {
pokazKsiazka(*ksiazka1);
dodajStrony(ksiazka1);
pokazKsiazka(*ksiazka1);
} else {
printf("Nie udalo sie utworzyc ksiazki.\n");
}
free(ksiazka1);
return 0;
}