Napisz program który po uruchomieniu wyświeli twoje imię i nazwisko. Skompiluj go za pomocą gcc
i uruchom z terminala.
./a.out
$ Jan Kowalski
#include <stdio.h>
int main(void)
{
("Jan Kowalski\n");
printfreturn 0;
}
Znak \n
to znak nowej linii (czyli “enter”).
Następnie:
$ gcc main.c -o imieinazwisko
$ ./imieinazwisko
Jak Kowalski
Napisz program który przyjmuje 2 argumenty: imie i nazwisko, a następnie je wyświetla.
./a.out Przemyslaw Czarnota
$
Przemyslaw Czarnota?
$ echo $0
Podanie niepoprawnej liczby argumentów, powinno skutkować wyświetleniem błędu na standardowy strumień błędów oraz zwróceniem kodu błędu różnego od 0.
$ ./a.out Za duzo argumentow >/dev/null
error: wrong number of arguments
$ echo $?
1
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc != 3) {
(stderr, "error: wrong number of arguments\n");
fprintfreturn 1;
}
("%s %s\n", argv[1], argv[2]);
printfreturn 0;
}
Gdy uruchamiamy ./program Jan Kowalski
, system operacyjny jako drugi argument funkcji main()
przekazuje następującą tablicę ciągów znaków:
char *argv[] = { "./program", "Jan", "Kowalski" };
Warto zauważyć że wywołanie systemowe execvp
przyjmuje podobny argument :)
Napisz program, który będzie odczytywał ze standardowego wejścia liczby do momentu wystąpienia wejścia, które nie jest liczbą lub końca strumienia i na końcu wyświetli ich średnią arytmetyczną.
./a.out
$ 1
2
3 <--- tu wcisnąłem Ctrl-d
2.000000
Przydatne funkcje:
scanf()
- odczytuje zmienne ze standardowego wejściaSkrót klawiaturowy Ctrl-d
, powoduje wysłanie znaku końca pliku.
#include <stdio.h>
int main(void)
{
int sum = 0;
int count = 0;
while (1) {
int number;
int num = scanf("%d", &number);
if (num != 1)
break;
+= number;
sum ++;
count}
("%f\n", (float)sum / count);
printfreturn 0;
}
#include <stdio.h>
int main(void)
{
int sum = 0, count = 0, number;
while (scanf("%d", &number) == 1) {
+= number;
sum ++;
count}
("%f\n", (float)sum / count);
printfreturn 0;
}
Napisz program, który będzie odczytywał liczby ze standardowego wejścia i wypisze je w odwrotnej kolejności.
1 3 | ./a.out
$ seq 3
2
1
Program powinien działać maksymalnie dla 4096 liczb całkowitych. Dalsze liczby są odrzucane.
Do rozwiązania będzie potrzebne wykorzystanie tablicy. Na przykład
int tablica[4096];
#include <stdio.h>
int main(void)
{
int numbers[4096];
int count = 0;
int number;
/* Dopóki liczby są na standardowym wejściu */
while (1 == scanf("%d", &number)) {
if (count >= 4096)
break;
[count] = number;
numbers++;
count}
for (int i = count - 1; i >= 0; --i)
("%d\n", numbers[i]);
printf
return 0;
}
Napisz program który wyświetli wszystkie argumenty przekazane do programu
./a.out a b d e foo bar
$
a
b
d
e
foo bar
#include <stdio.h>
int main(int argc, char **argv)
{
for (int i = 1; i < argc; ++i)
("%s\n", argv[i]);
printf
return 0;
}
Napisz program, który będzie odczytywał ze standardowego wejścia liczby do momentu wystąpienia wejścia, które nie jest liczbą lub końca strumienia i na końcu wyświetli najmniejszą liczbę. Program powinien też działać dla liczb ujemnych.
./a.out
$ 1
-2
2
-1
-2 <--- tu wcisnąłem Ctrl-d co powoduje wyświetlenie wyniku
Przydatne funkcje:
scanf()
- odczytuje zmienne ze standardowego wejścia#include <stdio.h>
int main(int argc, char **argv)
{
int min, number;
if (1 != scanf("%d", &min))
return 0;
while (1 == scanf("%d", &number)) {
if (number < min)
= number;
min }
("%d\n", min);
printf
return 0;
}
Rozwiń program z Zadania 4, tak aby działał dla dowolnej ilości liczb, która jest podana jako pierwszy argument.
./a.out 5
1
2
3
4
5
5
4
3
2
1
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int max_count, count = 0, number;
if (argc != 2)
return 1;
if (1 != sscanf(argv[1], "%d", &max_count))
return 1;
int *numbers = malloc(max_count * sizeof(numbers[0]));
/* Dopóki liczby są na standardowym wejściu */
while (count < max_count && 1 == scanf("%d", &number)) {
[count] = number;
numbers++;
count}
for (int i = count - 1; i >= 0; --i)
("%d\n", numbers[i]);
printf
(numbers);
freereturn 0;
}
Rozwiń program z Zadania 4, tak aby działał dla dowolnej ilości liczb, ale bez podawania maksymalnej ilości liczb jako pierwszy argument. Wewnętrzna tablica powinna się dynamicznie rozszerzać.
Przydatne funkcje:
malloc()
- alokuje pamięćrealloc()
- realokuje pamięćfree()
- zwalnia pamięćmemcpy()
- kopiuje daneSprawdź czy nie ma wycieków pamięci:
$ valgrind --leak-check=full --show-leak-kinds=all ./program
$ gcc main.c -fsanitize=address -o program
$ ./program
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int *numbers = NULL; /* realloc(NULL, ...) i free(NULL) jest ok */
int count = 0;
int number;
while (1 == scanf("%d", &number)) {
= realloc(numbers, (count + 1) * sizeof(numbers[0]));
numbers if (!numbers)
goto out; /* goto nie jest "złe", jeżeli używamy do obsługi błędów */
[count] = number;
numbers++;
count}
for (int i = count - 1; i >= 0; --i)
("%d\n", numbers[i]);
printf:
out(numbers);
freereturn 0;
}
Napisz program który będzie działał jak program yes
.
./program | head -n 3
$
y
y y
./program no | head -n 3
$
no
no no
Z tą drobną różnicą, że będzie obsługiwał tylko jeden argument.
#include <stdio.h>
int main(int argc, char **argv)
{
while (1)
("%s\n", argc >= 2 ? argv[1] : "y");
printfreturn 0;
}
Napisz funkcję która będzie sortować tablicę liczb typu int
algorytmem sortowania bąbelkowego. Pseudokod:
sort(items, len) {
for (i = 0; i < len - 1; i++) {
for (j = 0; j < len - 1 - i; j++) {
if (items[j] > items[j + 1])
swap(items[j], items[j + 1]);
}
}
}
Wykorzystanie:
int n[] = {8, 3, 4, 5, 6, 7, 8};
(n, 7); sort
void sort(int *items, unsigned int len)
{
for (unsigned int i = 0; i < len - 1; ++i) {
for (unsigned int j = 0; j < len - 1 - i; j++) {
if (items[j] > items[j + 1]) {
int tmp = items[j];
[j] = items[j + 1];
items[j + 1] = tmp;
items}
}
}
}
Napisz funkcję która będzie sortować tablicę liczby typu float
algorytmem sortowania bąbelkowego. Dodaj do niej parametr określający porządek sortowania.
void sort_float(float *items, unsigned int len, bool reversed);
Wykorzystanie:
float n[] = {8.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
(n, 7, false); sort_float
void sort_float(float *items, unsigned int len, bool reversed)
{
for (unsigned int i = 0; i < len - 1; ++i) {
for (unsigned int j = 0; j < len - 1 - i; j++) {
bool swap;
if (reversed)
= items[j] < items[j + 1];
swap else
= items[j] > items[j + 1];
swap
if (swap) {
float tmp = items[j];
[j] = items[j + 1];
items[j + 1] = tmp;
items}
}
}
}
Zdefiniuj makro ARRAY_SIZE()
, które pozwoli obliczać liczbę elementów w tablicy w trakcie kompilacji (jeżeli rozmiar jest znany w trakcie kompilacji)
int n[] = {8, 3, 4, 5, 6, 7, 8};
(n, ARRAY_SIZE(n)); sort
float n[] = {8.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
(n, ARRAY_SIZE(n)); sort_float
Przydatny operator:
sizeof(x)
- podaje rozmiar wyrażenia#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
Napisz generyczną funkcję sort()
, która może posortować tablicę dowolnego typu:
void sort(void *ptr, unsigned int count, unsigned int element_size,
int (*comparator)(const void *a, const void *b));
int compare_double(const void *__a, const void *__b)
{
const double *a = __a, *b == __b;
if (*a == *b)
return 0;
return *a < *b ? -1 : 1;
}
double items[] = { 2.0f, 8.0f, -1.0f, 3.0f };
(items, ARRAY_SIZE(items), sizeof(items[0]), compare_double); sort
Funkcja powinna dawać taki sam efekt jak qsort()
.
#include <string.h>
void sort(void *array, int count, unsigned int elem_size,
int (*compare)(const void *a, const void *b))
{
for (int i = 0; i < count - 1; ++i) {
for (int j = 0; j < count - 1 - i; j++) {
void *a = array + j * elem_size;
void *b = array + (j + 1) * elem_size;
if (compare(a, b) >= 1) {
unsigned char tmp[elem_size];
(tmp, a, elem_size);
memcpy(a, b, elem_size);
memcpy(b, tmp, elem_size);
memcpy}
}
}
}
Napisz program który jako pierwszy argument przyjmie ciąg znaków. Następnie wypisze ciąg znaków, zamieniając wszystkie duże litery na małe.
./program "This Should Be Small 1234"
$ 1234 this should be small
Zamiana znaków powinna się dokonać z wykorzystaniem autorskiej funkcji
void autorskafunkcjadozamianyznakow(char *str);
Przydatne informacje:
memcpy()
, strncpy()
, strcpy()
, snprintf()
.'a' - 'A'
.'A' <= litera && litera <= 'Z'
.to_lower()
void to_lower(char *str)
{
unsigned int len = strlen(str);
for (unsigned int i = 0; i < len; ++i) {
if ('A' <= str[i] && str[i] <= 'Z') {
[i] += 'a' - 'A';
str}
}
}
main()
#include <stdio.h>
void to_lower(char *str) { ... }
int main(int argc, char **argv)
{
if (argc != 2)
return 1;
char str[256];
int size = snprintf(str, sizeof(str), "%s", argv[1]);
if (size >= sizeof(str))
return 1;
(str);
to_lower
("%s\n", str);
printf
return 0;
}
Terminalem, na który wypisujemy można sterować specjalnymi kodami ANSI (https://en.wikipedia.org/wiki/ANSI_escape_code). Możemy w ten sposób na przykład:
(stderr, "%c[2J", 0x1b); /* Wyczyścić ekran */
fprintf(stderr, "%c[%d;%dH", 0x1b, y, x); /* Umieścić kursor w wierszu y i kolumnie x */ fprintf
Napisz 2 funkcje:
/* Czyści ekran */
void clrscr(void);
/* Umieszcza kursor w wierszu y i kolumnie x */
void gotoxy(int x, int y);
Narysuj za ich pomocą animację przypominającą “kod z matrixa”. Do generowania liczb losowych możesz użyć rand()
. Do kontroli szybkości animacji usleep()
.
void gotoxy(int x, int y)
{
(stderr, "%c[%d;%dH", 0x1b, y, x);
fprintf}
void clrscr(void)
{
(stderr, "%c[2J", 0x1b);
fprintf}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void gotoxy(int x, int y) { ... }
void clrscr(void) { ... }
int main(void)
{
();
clrscrwhile (1) {
int column = rand() % 79 + 1;
int len = rand() % 24;
for (int i = 1; i < len; ++i) {
(column, i);
gotoxychar c = rand() % 30 + 50;
(stderr, "%c", c);
fprintf(column, i);
gotoxy(50000);
usleep}
}
}