-
Notifications
You must be signed in to change notification settings - Fork 5
/
C
1389 lines (1004 loc) · 51.3 KB
/
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
kompilacja programu na kali linxie --> gcc -m64 hello.c -o hello
(hello.c to nazwa programu)
------------------------------------------------------------------------
|_|_|_|_|w3schools.com|_|_|_|_|
------------------------------------------------------
#include <stdio.h> to biblioteka plików nagłówkowych , która pozwala nam pracować z funkcjami wejścia i wyjścia, takimi jak printf(). Pliki nagłówkowe dodają funkcjonalność do programów C. (Czyli coś jak import w pythonie)
main(). Nazywa się to funkcją . Każdy kod w nawiasach klamrowych {}zostanie wykonany.
printf działą tak samo jak print w pythonie czyli 'drukuje' wynik np. printf("Witaj!");
Każda instrukcja C kończy się średnikiem ;
Linia 5: return 0 kończy main()funkcję.
A to wszystko dotyczy kodu "Hello World" czyli:
```
#include <stdio.h>
int main() {
printf("Hello World");
return 0;
}
```
Można użyć printf wielokronie np:
printf("hello world");
printf("Test nastepny");
Ale wtedy wydrukuje sięwszystko w jednej lini więc na końcu trzeba dodać \n np:
```
printf("hello world\n");
printf("Test Nastepny\n");
```
Wtedy kazdy komunikat pojawi się w nowej lini.
a \n\n zrobi jedną pustą linie np.
`printf("hello world\n\n");`
Znak nowej linii ( \n) nazywany jest sekwencją wyjściową i zmusza kursor do zmiany pozycji na początek następnej linii na ekranie. W rezultacie powstaje nowa linia.
Przykłady innych prawidłowych sekwencji specjalnych to:
\t <-- to po prostu spacja w jedenj lini
\\ <-- to dodaje znak \ do słowa
\" to dodaje znak " między dwoma słowami np.
tak wygląda wynik: hello"other
komentarze:
w jednym wierszy --> //
w wielu wierszach początek /* koniec */
**W C istnieją różne typy zmiennych (definiowane za pomocą różnych słów kluczowych), na przykład:**
int - przechowuje liczby całkowite (liczby całkowite), bez miejsc po przecinku, takie jak 123lub-123
float - przechowuje liczby zmiennoprzecinkowe, z miejscami dziesiętnymi, takimi jak 19.99lub-19.99
char - przechowuje pojedyncze znaki, takie jak 'a'lub 'B'. Wartości char są ujęte w pojedyncze cudzysłowy
Deklarowanie (tworzenie zmienny):
trzeba określić typ i wartość np.
float myNum = 20.99;
wytłumaczenie: float to typ zmiennej, myNum to nazwa wartości (jak x lub myname) znak równości przypisuje wartość w tym przypadku to 20.99
Możesz także zadeklarować zmienną bez przypisywania wartości i przypisać wartość później:
```
// deklaracja zmiennej
int = myNum;
// przypisanie wartości do zmiennej
myNum = 15;
```
Normalnie w takim języku jak python wystareczyło by użycie print aby wudrukować wynik w zmiennej czyli:
int myNum = 15;
print(myNum)
Ale nie w C, tutaj jest coś takiego jak **specyfikator formatu**
Specyfikatory formatu są używane razem z printf() funkcją, aby powiedzieć kompilatorowi, jaki typ danych przechowuje zmienna. Zasadniczo jest to symbol zastępczy dla wartości zmiennej.
Specyfikator formatu zaczyna się od znaku procentu %, po którym następuje znak.
Na przykład, aby wypisać wartość zmiennej int, musisz użyć specyfikatora formatu %dlub %i otoczonego podwójnymi cudzysłowami wewnątrz printf()funkcji:
int main(){
int myNum = 15;
printf("%d", myNum); //Wynik będzie 15
return 0;
}
z czego %c jest do char a %f do float, %lf do double, %s do strings
Aby wydrukować inne typy, użyj %cdla chari %fdla float:
```
#include <stdio.h>
int main(){
int myNum = 20;
float myFloatNum = 15.66;
char myLatter = 'B';
printf("%i\n", myNum);
printf("%f\n", myFloatNum);
printf("%c\n", myLatter);
return 0;
}
```
Aby połączyć zarówno tekst, jak i zmienną, oddziel je przecinkiem wewnątrz printf()funkcji:
```
#include <stdio.h>
int main(){
int myNum = 15;
printf("Pokaż liczbe: %d", myNum);
return 0;
}
```
Aby drukować różne typy w jednej printf()funkcji, możesz użyć następujących opcji:
```
#include <stdio.h>
int main(){
int myNum = 20;
char myLatter = 'A';
printf("Moja ulubiona liczba to %i a Litera to %c", myNum, myLatter);
return 0;
}
```
Możesz także przypisać wartość jednej zmiennej do drugiej:
```
#include <stdio.h>
int main(){
int myNum = 15;
int myOtherNum = 30;
myNum = myOtherNum;
printf("%i", myNum);
return 0;
}
```
Aby dodać zmienną do innej zmiennej, możesz użyć + operatora:
#include <stdio.h>
```
int main(){
int x = 50;
int y = 21;
int sum = x + y;
printf("%i", sum);
return 0;
}
```
dodawanie kilku do hedenj wartości
#include <stdio.h>
```
int main(){
int x = 50, y = 20, z = 34;
printf("%i", x + y + z);
return 0;
}
```
lub:
```
#include <stdio.h>
int main(){
int x = 50, y = 20, z = 34;
int sum = x + y + z;
printf("%i", sum);
return 0;
}
```
(to to samo ale zapisane w inny sposób)
C Nazwy zmiennych
Wszystkie zmienne C muszą być identyfikowane za pomocą unikalnych nazw
Te unikalne nazwy są nazywane identyfikatorami .
Identyfikatorami mogą być nazwy krótkie (takie jak x i y) lub bardziej opisowe (wiek, suma, totalVolume).
czyli np.
int age = 22;
jest bardziej zrozumiałe niż
int a = 22;
Ogólne zasady nazewnictwa zmiennych to:
1. Nazwy mogą zawierać litery, cyfry i podkreślenia
2. Nazwy muszą zaczynać się od litery lub znaku podkreślenia (_)
3. W nazwach rozróżniana jest wielkość liter ( myVari myvarsą to różne zmienne)
4. Nazwy nie mogą zawierać spacji ani znaków specjalnych, takich jak !, #, % itp.
5. Zarezerwowane słowa (takie jak int) nie mogą być używane jako nazwy.
## Przykład z życia wzięty
Często w naszych przykładach upraszczamy nazwy zmiennych, aby pasowały do ich typu danych (myInt lub myNum dla inttypów, myChar dla chartypów itp.). Odbywa się to w celu uniknięcia zamieszania.
Jeśli jednak szukasz przykładu z życia wziętego, jak można wykorzystać zmienne, spójrz na poniższy program, w którym stworzyliśmy program przechowujący różne dane studenta:
#include <stdio.h>
```
int main() {
int studentID = 77;
int studentAGE = 19;
int studentCLASS = 3;
char studentSUM = 'A';
printf(" Student ID %i\n\n", studentID);
printf(" Student Age %i\n\n", studentAGE);
printf(" Student Class %i\n\n", studentCLASS);
printf(" Student general rating is %c\n\n", studentSUM);
return 0;
}
```
**int** |2 lub 4 bajty| Przechowuje liczby całkowite, bez części dziesiętnych
**float** |4 bajty| Przechowuje liczby ułamkowe zawierające jedną lub więcej cyfr dziesiętnych. Wystarczający do przechowywania 6-7 cyfr dziesiętnych
**double** |8 bajtów| Przechowuje liczby ułamkowe zawierające jedną lub więcej cyfr dziesiętnych. Wystarczający do przechowywania 15 cyfr dziesiętnych
**char** |1 bajt| Przechowuje pojedynczy znak/literę/cyfrę lub wartości ASCII
**strings**(%s) to pewnie do całych słów typu 'car'
przykład z double;
```
#include <stdio.h>
int main() {
float myFloatNum = 1.99;
double mydoubleNum = 39.55;
printf("%f\n", myFloatNum);
printf("%lf", mydoubleNum);
return 0;
}
```
Jeśli chcesz usunąć dodatkowe zera (ustawić dokładność dziesiętną), możesz użyć kropki ( .), po której następuje liczba określająca, ile cyfr ma być wyświetlanych po przecinku:
```
#include <stdio.h>
int main(){
float myfloatNum = 9.5;
printf("%f\n", myfloatNum); // Pokaże normalny wynik (czyli 9.500000)
printf("%.1f\n", myfloatNum); // pokaze 1 liczbe po przecinku (czyli 9.5)
printf("%.2f\n", myfloatNum); // to samo co powyzej tylko 2 (czyli 9.50)
printf("%.4f\n", myfloatNum); // to samo
return 0;
}
```
## Konwersja typów
Czasami trzeba przekonwertować wartość jednego typu danych na inny typ. Jest to znane jako konwersja typu .
Na przykład, jeśli spróbujesz podzielić dwie liczby całkowite 5przez 2, spodziewasz się, że wynikiem będzie 2.5. Ale ponieważ pracujemy z liczbami całkowitymi (a nie zmiennoprzecinkowymi), poniższy przykład po prostu wyświetli 2:
```
#include <stdio.h>
int main(){
int x = 5;
int y = 2;
int sum = 5 / 2;
printf("%i", sum);
return 0;
}
```
Istnieją dwa rodzaje konwersji w C:
**Niejawna konwersja** (automatycznie)
**Jawna konwersja** (ręcznie)
przykładowy kod:
```
int myint = 9.99;
printf("%d", myint); // Wynik będzie 9
```
co się stało .99? Możemy chcieć tych danych w naszym programie! Więc uważaj. Ważne jest, aby wiedzieć, jak kompilator działa w takich sytuacjach, aby uniknąć nieoczekiwanych wyników.
Jako inny przykład, jeśli podzielisz dwie liczby całkowite: 5przez 2, wiesz, że suma wynosi 2.5. A jak wiesz z początku tej strony, jeśli zapiszesz sumę jako liczbę całkowitą, wynik wyświetli tylko liczbę 2. Dlatego lepiej byłoby zapisać sumę jako a floatlub a double, prawda?
```
float sum = 5 / 2;
printf("%f", sum); // wynik to 2.00000
```
Dlaczego jest wynik, 2.00000a nie 2.5? Cóż, to dlatego, że 5 i 2 są nadal liczbami całkowitymi w dzieleniu. W takim przypadku należy ręcznie przekonwertować wartości całkowite na wartości zmiennoprzecinkowe. (patrz poniżej).
**Jawna Konwersja:**
```
#include <stdio.h>
int main(){
float sum = (float) 5 / 2;
printf("%.1f", sum); // Wynik to 2.5
return 0;
}
```
## Stałe
Jeśli nie chcesz, aby inni (lub ty) zmieniali istniejące wartości zmiennych, możesz użyć słowa constkluczowego.
Spowoduje to zadeklarowanie zmiennej jako „stałej”, co oznacza niezmienną i tylko do odczytu :
const int myNum = 15; // Teraz cały czas będzie liczba 15
myNum = 10; // To bedzie error bo stała liczba to 15
Powinieneś zawsze deklarować zmienną jako stałą, gdy masz wartości, które prawdopodobnie się nie zmienią czyli np 1 minuta ma 60 sekund, a PI to 3.14 np:
```
#include <stdio.h>
int main(){
const int secoundsinminute = 60;
const float PI = 3.14;
printf("%i\n", secoundsinminute);
printf("%f", PI);
return 0;
}
```
Uwagi dotyczące stałych
Kiedy deklarujesz stałą zmienną, musisz jej przypisać wartość:
Przykład
Lubię to:
```
const int minutesPerHour = 60;
```
To jednak nie zadziała :
```
const int minutesPerHour;
minutesPerHour = 60; // error
```
Dobra praktyka
Inną rzeczą związaną ze stałymi zmiennymi jest to, że dobrą praktyką jest deklarowanie ich wielkimi literami. Nie jest to wymagane, ale przydatne dla czytelności kodu i wspólne dla programistów C:
const int GOOD = 10;
## Operators
Operatory służą do wykonywania operacji na zmiennych i wartościach.
W poniższym przykładzie używamy + operatora , aby dodać dwie wartości:
int myNum = 100 + 50;
Chociaż +operator jest często używany do dodawania dwóch wartości, jak w powyższym przykładzie, może być również używany do dodawania zmiennej i wartości lub zmiennej i innej zmiennej:
int sum1 = 100 + 50;
int sum2 = sum1 + 250; // 150 + 250 = 400
int sum3 = sum2 + sum2; // = 400 + 400 = 800
C dzieli operatorów na następujące grupy:
Operatory arytmetyczne
Operatory przypisania
Operatory porównania
Operatory logiczne
Operatory bitowe
Operatory arytmetyczne
Operatory arytmetyczne służą do wykonywania typowych operacji matematycznych.
czyli: +, -, /, *, ++, --, %
% Moduł Zwraca resztę z dzielenia x % y
++ Increment Zwiększa wartość zmiennej o 1 ++x
-- Decrement Zmniejsza wartość zmiennej o 1 --x
Operatory przypisania
Operatory przypisania służą do przypisywania wartości do zmiennych.
dodanie wartości np. do istniejącej
int x = 10;
int x += 5;
![c392cbd88107bb6f6c4c40cfe40261e5.png](:/f33264226a694a4286b82b721dd7a1ac)
Operatory porównania
Operatory porównania służą do porównywania dwóch wartości (lub zmiennych). Jest to ważne w programowaniu, ponieważ pomaga nam znaleźć odpowiedzi i podejmować decyzje.
Wartością zwracaną przez porównanie jest albo 1albo 0, co oznacza prawdę ( 1) lub fałsz ( 0). Te wartości są znane jako wartości logiczne i dowiesz się o nich więcej w rozdziale Boolean i If..Else .
W poniższym przykładzie używamy operatora większego niż ( >), aby dowiedzieć się, czy 5 jest większe niż 3:
int x = 5;
int y = 3;
printf("%i", x > y); // wynik bedzie 1 (prawda) ponieważ 5 jest lepsze niż 3
![fcd13c467d5d9541aa177810a9544091.png](:/1bf2707b5cb1485e91f1a55bc895e4ad)
Operatory logiczne
Za pomocą operatorów logicznych można również testować wartości prawda lub fałsz.
Operatory logiczne służą do określenia logiki między zmiennymi lub wartościami:
![daea3999f9c92ec315b67c044d2655ac.png](:/c4753c93c21d46dfb33f4c8388a157bf)
Rozmiar operatora
Rozmiar pamięci (w bajtach) typu danych lub zmiennej można znaleźć za pomocą operatora sizeof:
#include <stdio.h>
int main(){
int myint;
float myfloat;
char mychar;
double mydouble;
printf("%lu\n", sizeof(myint)); // wyniki: 4 bajty
printf("%lu\n", sizeof(myfloat)); // 4 bajty
printf("%lu\n", sizeof(mychar)); // 1 bajt
printf("%lu\n", sizeof(mydouble)); // 8 bajtów
return 0;
}
**Zauważ, że do wydrukowania wyniku używamy %luspecyfikatora formatu zamiast %d. Dzieje się tak dlatego, że kompilator oczekuje, że operator sizeof zwróci znak long unsigned int( %lu), zamiast int( %d). Na niektórych komputerach może działać %d, ale jest bezpieczniejszy w użyciu %lu.**
## Logiczne
Bardzo często w programowaniu będziesz potrzebować typu danych, który może mieć tylko jedną z dwóch wartości, na przykład:
TAK NIE
WŁ. / WYŁ
PRAWDA FAŁSZ
W tym celu C ma booltyp danych, który jest znany jako booleans .
Logiczne reprezentują wartości, które są albo truealbo false.
## Zmienne logiczne
W C booltyp nie jest wbudowanym typem danych, takim jak intlub char.
Został wprowadzony w C99 i aby go użyć, należy zaimportować następujący plik nagłówkowy:
`#include <stdbool.h>`
Zmienna logiczna jest deklarowana za pomocą boolsłowa kluczowego i może przyjmować tylko wartości truelub false:
bool ishackingfunny = false;
bool ishackinggood = true;
Zanim spróbujesz wydrukować zmienne logiczne, powinieneś wiedzieć, że wartości logiczne są zwracane jako liczby całkowite:
1(lub dowolna inna liczba, która nie jest 0) reprezentujetrue
0reprezentujefalse
Dlatego musisz użyć %d specyfikatora formatu, aby wydrukować wartość logiczną:
```
#include <stdio.h>
#include <stdbool.h>
int main(){
bool ishackingfunny = false;
bool ishackinggood = true;
printf("%d\n", ishackingfunny); // odp 0
printf("%d", ishackinggood); // odp 1
return 0;
}
```
0 = Fałsz
jaka kolwiek liczba powyzej 0 = Prawda
**Jednak bardziej powszechne jest zwracanie wartości logicznej przez porównywanie wartości i zmiennych.**
## Porównanie wartości i zmiennych
Porównywanie wartości jest przydatne w programowaniu, ponieważ pomaga nam znaleźć odpowiedzi i podejmować decyzje.
Na przykład możesz użyć operatora porównania , takiego jak operator większy niż ( >), aby porównać dwie wartości:
printf("%d", 10 > 9); // Wynik będzie 1 (Prawda) Bo 10 jest większy niż 9.
W poniższym przykładzie używamy operatora równości ( ==) do porównywania różnych wartości:
```
printf("%d", 10 == 10); // wynik będzie 1 (True) bo 10 i 10 jest equal
printf("%d", 5 == 55); // False bo 5 jest mniejsze
printf("%d", 10 == 15); // False
```
Nie jesteś ograniczony tylko do porównywania liczb. Możesz także porównywać zmienne boolowskie, a nawet specjalne struktury, takie jak tablice
```
bool chamburgerisgood = true;
bool Pizzajestdobra = true
printf("%d", chamburgerisgood == Pizzajestdobra);
```
Przykład z życia wzięty
Pomyślmy o „przykładzie z życia”, w którym musimy dowiedzieć się, czy dana osoba jest wystarczająco dorosła, aby głosować.
W poniższym przykładzie używamy >=operatora porównania, aby dowiedzieć się, czy wiek ( 25) jest większy niż LUB równy limitowi wiekowemu uprawniającemu do głosowania, który jest ustawiony na 18:
int myAge = 20;
int VotingAge = 18;
prntf("%d", myAge >= VotingAge); // odp 1 (prawda) bo 20 jest wieksze niz 18 // czyli jest dozwolone
Jeszcze lepszym podejściem (ponieważ jesteśmy teraz na fali) byłoby zawinięcie powyższego kodu w instrukcję if...else, abyśmy mogli wykonać różne akcje w zależności od wyniku:
**Przykład**
Dane wyjściowe „Wystarczająco duży, aby głosować!” jeśli myAgejest większe lub równe 18 . W przeciwnym razie wypisz „Niewystarczająco stary, aby głosować.”:
```
#include <stdio.h>
int main(){
int myAge = 14;
int voteAge = 18;
if (myAge >= voteAge){
printf("you are Old enough to Vote!");
} else {
printf("you are not Old enough to Vote");
}
} // Wynik to będzie że nie wystarczająco dorosły bo 14, ale jak zmienie na np. 18 i pwyzej juz wystarczająco dorosły.
```
![7b26bdc3e86a78a86ca413495439a29c.png](:/055b254ef30d43d084f062515f388c43)
## Instrukcja if
Użyj ifinstrukcji, aby określić blok kodu, który ma zostać wykonany, jeśli warunek to true.
np.
```
if (20 > 18) {
printf("20 jest lepsze niz 18!");
}
```
Możemy również testować zmienne:
```
int x = 20;
int y = 18;
if (x > y) {
printf("x jest lepsze niz y");
}
```
W powyższym przykładzie używamy dwóch zmiennych, x i y , aby sprawdzić, czy x jest większe niż y (za pomocą >operatora). Skoro x to 20, a y to 18, i wiemy, że 20 jest większe niż 18, wypisujemy na ekranie, że „x jest większe niż y”.
## Oświadczenie else
Użyj elseinstrukcji, aby określić blok kodu, który ma zostać wykonany, jeśli warunek to false. np.
```
#include <stdio.h>
int main() {
int time = 20;
if (time < 18) {
printf("Good Morning");
} else {
printf("Good evening");
}
return 0;
}
```
W powyższym przykładzie czas (20) jest większy niż 18, więc warunek to false. Z tego powodu przechodzimy do elsestanu i drukujemy na ekranie „Dobry wieczór”. Jeśli czas był krótszy niż 18, program wydrukowałby „Dzień dobry”.
## Instrukcja else if
Użyj else ifinstrukcji, aby określić nowy warunek, jeśli pierwszy warunek to false.
np.
```
#include <stdio.h>
int main(){
int time = 20;
if (time < 10) {
printf("Good morning");
} else if (time < 20) {
printf("good day");
} else {
printf("good evening");
}
return 0;
}
```
W powyższym przykładzie czas (22) jest większy niż 10, więc pierwszym warunkiem jest false. Następnym warunkiem w else ifinstrukcji jest również false, więc przechodzimy do else warunku, ponieważ warunek 1 i warunek 2 są obydwoma false- i wypisujemy na ekranie „Dobry wieczór”.
Jeśli jednak czas wynosiłby 14, nasz program wydrukowałby „Dzień dobry”.
------------------------------------------------------------------------
|_|_|_|_|WIKIPEDIA|_|_|_|_|
------------------------------------------------------
Arrays to tablice
Tablice to specjalne zmienne, które mogą przechowywać więcej niż jedną wartość pod tą samą nazwą zmiennej, zorganizowane za pomocą indeksu. Tablice są definiowane przy użyciu bardzo prostej składni:
**if ... else** – pozwala na wykonanie jednej z dwóch gałęzi kodu na podstawie wartości typu logicznego,
**switch** – wykonuje jeden z wielu bloków kodu na podstawie porównania wartości liczbowej z wyrażeniami w poszczególnych etykietach case.
Druga grupa instrukcji sterujących służy realizacji pętli. Każda z nich jest wykonywana tak długo, jak podany warunek jest prawdziwy. Składają się na nią:
**while** – warunek jest sprawdzany przed każdą iteracją;
**do ... while** – warunek jest sprawdzany po każdej iteracji;
**for** – pozwala na określenie instrukcji, która wykona się przed pierwszą iteracją oraz instrukcji do wywołania po każdym przebiegu pętli.
Ostatnią grupę stanowią instrukcje skoku (Instrukcja skoku – instrukcja w językach programowania, która powoduje przekazanie sterowania w inne miejsce, tzw. skok.) Należą do nich:
**goto** – realizuje skok do etykiety o podanej nazwie, ale nie jest możliwe wyjście z aktualnie wykonywanej funkcji;
**continue** – przerywa wykonywanie bieżącej iteracji pętli i przechodzi do kolejnej;
**break** – przerywa wykonywanie pętli lub instrukcji switch;
**return** – przerywa wykonywanie bieżącej funkcji i opcjonalnie przekazuje wartość do miejsca wywołania.
Preprocesor w języku C pozwala na manipulację kodem źródłowym przed właściwą kompilacją. Wspiera mechanizmy kompilacji warunkowej (dyrektywa #if i jej warianty) oraz dołączania innych plików źródłowych (#include). Odpowiada również za rozwijanie makr (zdefiniowanych przy użyciu #define)
Dzięki dyrektywie #pragma możliwe jest przekazywanie instrukcji specyficznych dla kompilatora.
W trakcie kompilacji, komentarze zastępowane są znakiem spacji
Typ danych określa zbiór wartości, które może przyjąć dany obiekt, jak również dozwolone operacje na nim[57]. Język udostępnia zestaw typów podstawowych oraz mechanizmów konstruowania typów pochodnych[58].
Szczególnym typem danych w C jest typ pusty void, który nie przechowuje żadnej wartości. W związku z tym można wykorzystywać go jedynie w sytuacjach, gdy wartość nie jest wymagana – np. jako lewy argument operatora , lub w charakterze instrukcji. Rzutowanie tego typu na jakikolwiek inny typ, zarówno jawne, jak i niejawne jest niedozwolone[59]. Słowem void oznacza się między innymi funkcje nie zwracające nic
Typy podstawowe
W języku C istnieje kilka bazowych typów danych, które można dookreślać z użyciem odpowiednich słów kluczowych w celu uzyskania odpowiedniego zakresu wartości. Służą do przechowywania liczb całkowitych (char i int) oraz zmiennoprzecinkowych (float i double)[61].
Razem z typem int można stosować kwalifikatory short oraz long. Pozwalają one programiście wykorzystywać typy danych krótsze i dłuższe niż naturalne dla danej architektury. Ponadto nazwę każdego typu, służącego do przechowywania liczb całkowitych, można również poprzedzić słowem signed lub unsigned, aby określić, czy dany obiekt ma być w stanie przechowywać liczby ujemne[62]. Reprezentacja bitowa wartości, które można zapisać zarówno w wariancie signed, jak i unsigned danego typu jest w obu wariantach taka sama[63].
Standard języka C nie ustala w sposób sztywny zakresów wartości, jakie muszą się zmieścić w obiektach poszczególnych typów. Podobnie nie są określone ich rozmiary w bitach lub bajtach[61]. Od implementacji języka wymaga się, by poszczególne typy danych pozwalały na przechowywanie przynajmniej liczb z ustalonego przedziału[32], a w przypadku typu logicznego _Bool – by miał rozmiar wystarczający do zmieszczenia wartości 0 i 1
![54b548cdc6e587799b3760edeb41adb5.png](:/32e1b865bb5e4379be666301671dccb5)
W powyższej tabeli zebrano minimalne wymagania stawiane dostępnym w C typom całkowitoliczbowym. Dodatkowym ograniczeniem, stawianym przez standard jest to, aby kolejne typy miały zakres niemniejszy od poprzednich. Na przykład obiekt typu short nie może być dłuższy niż int, który z kolei musi być niedłuższy od long
Użycie kwalifikatora long jest dopuszczalne również w połączeniu z typem double, choć standard C nie gwarantuje, że uzyskany w ten sposób typ będzie miał większą pojemność niż wyjściowy. Podobnie jak w przypadku liczb całkowitych, dostępne typy zmiennoprzecinkowe również nie mają sztywno określonego zakresu wartości oraz minimalnej dokładności
![9fee6d20a7f5f9648f91b2334a46858c.png](:/15db8fc5ee5540dab46cb8290e489ea0)
------------------------------------------------------------------------
|_|_|_|_|w3schools.com|_|_|_|_|
------------------------------------------------------
## Ternary Operator.
Istnieje również skrót if else, który jest znany jako operator trójskładnikowy , ponieważ składa się z trzech operandów. Można go użyć do zastąpienia wielu linii kodu pojedynczą linią. Jest często używany do zastąpienia prostych instrukcji if else:
czyli zamiast pisać:
```
int time = 18;
if (time < 18) {
printf("Good day");
} else {
printf("good night");
}
```
Mogę napisać
```
int time = 20;
(time < 18) ? printf("Good day") : printf("Good evening");
```
i to się nazywa **operator trójskładnikowy**
## Instrukcja przełączania
Zamiast pisać wieleif..else stwierdzeń, możesz użyć switchstwierdzeń.
Instrukcja switchwybiera jeden z wielu bloków kodu do wykonania:
Tak to działa:
Wyrażenie switchjest oceniane raz
Wartość wyrażenia jest porównywana z wartościami każdego z nichcase
Jeśli występuje dopasowanie, wykonywany jest powiązany blok kodu
Instrukcja breakwychodzi z bloku switch i zatrzymuje wykonanie
Instrukcja defaultjest opcjonalna i określa kod do uruchomienia, jeśli nie ma dopasowania wielkości liter
przykład na podstawie dni tygodnia:
```
#include <stdio.h>
int main() {
int day = 4;
switch (day) {
case 1:
printf("Poniedziałek");
break;
case 2:
printf("Wtorek");
break;
case 3:
printf("Sroda");
break;
case 4:
printf("Czwartek");
break;
case 5:
printf("Piątek");
break;
case 6:
printf("Sobota");
break;
case 7:
printf("NIedziela");
break;
}
return 0;
}
```
## Przerwa Słowo kluczowe
Kiedy C osiąga break słowo kluczowe, wyrywa się z bloku przełącznika.
Spowoduje to zatrzymanie wykonywania większej liczby testów kodu i przypadków w bloku.
Po znalezieniu dopasowania i zakończeniu pracy nadchodzi czas na przerwę. Więcej testów nie jest potrzebne.
**Przerwa może zaoszczędzić dużo czasu wykonania, ponieważ „ignoruje” wykonanie całej reszty kodu w bloku przełącznika.**
## Domyślne słowo kluczowe
Słowo defaultkluczowe określa kod do uruchomienia, jeśli nie ma dopasowania wielkości liter np:
```
#include <stdio.h>
int main(){
int day = 3;
switch (day) {
case 4:
printf("mondey");
break;
case 5:
printf("thusday");
break;
case 6:
printf("Wedneday");
break;
default:
printf("Hello my name is\n TEST!");
}
return 0;
}
```
## LOOPS
Pętle mogą wykonywać blok kodu, o ile spełniony jest określony warunek.
Pętle są przydatne, ponieważ oszczędzają czas, zmniejszają liczbę błędów i zwiększają czytelność kodu.
Podczas pętli
Pętla whileprzechodzi przez blok kodu tak długo, jak określony warunek to true:
W poniższym przykładzie kod w pętli będzie wykonywany w kółko, dopóki zmienna ( i) będzie mniejsza niż 5:
```
#include <stdio.h>
int main(){
int i = 0;
while (i < 400000) {
printf("%d\n", i);
i++;
}
return 0;
}
```
w tym przykładzie wynik będzie taki: pojawią się liczby od 0 do 399999 po kolei.
## Pętla Do/While
Pętla do/whilejest wariantem pętli while. Ta pętla wykona blok kodu raz, przed sprawdzeniem, czy warunek jest prawdziwy, a następnie będzie powtarzać pętlę, dopóki warunek jest prawdziwy.
Poniższy przykład wykorzystuje do/whilepętlę. Pętla zawsze zostanie wykonana co najmniej raz, nawet jeśli warunek jest fałszywy, ponieważ blok kodu jest wykonywany przed sprawdzeniem warunku:
```
int i = 0;
do {
printf("%d\n", i);
i++;
}
while (i < 20);
```
## for loops
Kiedy wiesz dokładnie, ile razy chcesz przejść przez blok kodu, użyj pętli forzamiast whilepętli:
Instrukcja 1 jest wykonywana (jeden raz) przed wykonaniem bloku kodu.
Instrukcja 2 definiuje warunek wykonania bloku kodu.
Instrukcja 3 jest wykonywana (za każdym razem) po wykonaniu bloku kodu.
Poniższy przykład wydrukuje liczby od 0 do 4:
```
int i;
for(i = 0; i < 5; i++) {
printf("%d\n", i);
}
```
**Przykład wyjaśniony**
Instrukcja 1 ustawia zmienną przed rozpoczęciem pętli (int i = 0).
Instrukcja 2 definiuje warunek wykonania pętli (i musi być mniejsze niż 5). Jeśli warunek jest prawdziwy, pętla rozpocznie się od nowa, jeśli jest fałszywy, pętla się zakończy.
Instrukcja 3 zwiększa wartość (i++) za każdym razem, gdy wykonywany jest blok kodu w pętli
inny przykład (W tym przykładzie zostaną wydrukowane tylko wartości parzyste z zakresu od 0 do 10):
```
int i;
for (i = 0; i <= 10; i = i + 2) {
printf("%d\n", i);
}
```
## Nested Loops
Możliwe jest również umieszczenie pętli w innej pętli. Nazywa się to pętlą zagnieżdżoną .
„Wewnętrzna pętla” zostanie wykonana jeden raz dla każdej iteracji „zewnętrznej pętli”:
```
#include <stdio.h>
int main() {
int i, j;
for (i = 1; i <= 2; ++i) {
printf("First: %d\n", i);
for (j = 1; j <= 3; ++j) {
printf("Two: %d\n", j);
}
return 0;
}
}
```
------------------------------------------------------------------------------------
|_|_|_|_|Bezpieczenstwo kodu_|_|_|_|
---------------------------------------------------------------
**W przypadku wywiadów dotyczących kodowania C przejrzyj następujące informacje**:
Przepełnienia/niedomiar liczb całkowitych: https://www.exploit-db.com/docs/english/28477-linux-integer-overflow-and-underflow.pdf
Przepełnienie bufora (stos/sterta): https://owasp.org/www-community/attacks/Buffer_overflow_attack
Luki w zabezpieczeniach ciągów formatu: https://owasp.org/www-community/attacks/Format_string_attack
Oprócz luk w zabezpieczeniach możesz spodziewać się, że ankieter zapyta Cię o podstawy wykorzystania. Możesz poczytać na:
1. NOP Sled
2. Return to libc
3. ROP
Na koniec powinieneś przejrzeć środki zaradcze/obrony, aby chronić się przed tymi lukami:
- [ ] ASLR/DEP
- [ ] Stack Canaries
- [ ] Control Flow Integrity
najlepszą praktyką może być całkowite unikanie tych zakazanych funkcji, widzę wiele projektów, w których niektóre z tych funkcji są używane, ale w bezpiecznych kontekstach. Jeśli podniesiesz czerwoną flagę po prostu za każdym razem, gdy zobaczysz, że jedna z tych funkcji jest w użyciu, możesz mieć zły czas.
Oto kilka przykładów użycia niesławnej strcpyi nieco bezpieczniejszej wersji strncpy:
```
void foo_1(char* bar) {
char buf[100];
strcpy(buf, bar);
puts(buf);
}
char* foo_2(char* bar) {
char* buf = NULL;
buf = malloc(strlen(bar)+1);
strcpy(buf, bar);
return buf; // freed later
}
void foo_3(char* bar) {
char buf[100];
strncpy(buf, bar, sizeof(buf));
puts(buf);
}
void foo_4() {
char buf[100];
strcpy(buf, "This is just an example.");
puts(buf);
}
```
Jeśli zrobiłem to poprawnie, te przykłady powinny wyglądać tak:
1. Niebezpieczne (jeśli barjest dłuższe niż 100 bajtów, nastąpi przepełnienie)
2. Bezpieczny (bufor jest tworzony wystarczająco duży)
3. Niebezpieczne (wytwarza niezakończony ciąg, gdy nie ma bajtów zerowych w pierwszych n bajtach bar)
4. Bezpieczny (ciąg jest stały i mniejszy niż rozmiar bufora)
Dodatkowo, chociaż funkcje z rodziny „strn” również mogą pojawić się na liście zakazanych, wiele projektów używa ich również bezpiecznie, wymuszając na końcu bajt zerowy, często za pomocą funkcji opakowującej.
statystyczna analiza kodu:
https://www.perforce.com/products/klocwork
Innym sposobem na zdefiniowanie stałej jest użycie dyrektywy preprocesora #define .
Dyrektywa #define używa makr do definiowania stałych wartości.
Na przykład:
```
#include <stdio.h>
#define PI 3.14
int main() {
printf("%f", PI);
return 0;
}
```
Różnica między const i #define polega na tym, że pierwsza używa pamięci do przechowywania, a druga nie.
https://github.com/ctfs/resources/tree/master/topics/binary-exploitation
AI: Najlepsze praktyki dotyczące organizowania kodu i pisania czystych, łatwych w utrzymaniu programów w C
Modularyzuj kod w funkcje oparte na dyskretnych zadaniach. Zachowaj małe funkcje.
Używaj opisowych nazw zmiennych, funkcji i plików. Unikaj skrótów.
Postępuj zgodnie ze spójną konwencją nazewnictwa, taką jak lower_snake_case.
Podziel duże zadania na mniejsze funkcje pomocnicze.
Ogranicz długości funkcji, aby poprawić czytelność.
Używaj spacji, znaków nowej linii i komentarzy swobodnie, aby poprawić czytelność.
Przechowuj powiązany kod zgrupowany w plikach nagłówkowych, źródłowych i testowych.
Zrozumienie różnych bibliotek C i frameworków
Poznaj standardową bibliotekę C, aby poznać podstawowe funkcje, takie jak wejście/wyjście, obsługa ciągów znaków i operacje matematyczne.
Korzystaj z bibliotek takich jak OpenSSL do kryptografii, zlib do kompresji, cURL do transferów internetowych.