Wstęp do Programowania, laboratorium 04, niestacjonarne Zadanie

Transkrypt

Wstęp do Programowania, laboratorium 04, niestacjonarne Zadanie
Wstęp do Programowania, laboratorium 04, niestacjonarne
Zadanie 1. Zrobić program liczący wartość funkcji sin(x) przy pomocy rozwinięcia w szereg.
Zakres wartości x (od, do) oraz liczba przedziałów podawane będą jako argumenty programu,
wyniki wpisywane będą do plików – dokładny do pliku „sin_dokladny.txt”, obliczony z szeregu „sin_szereg.txt”.
Przykładowe wywołanie programu:
./a.out -2 4 60
^ Policzy dla x od -2 do 4, 60 podprzedziałów
Przykładowa zawartość plików:
sin_dokladny.txt
sin_szereg.txt
x sin(x)
-2 0.2
-1.9 0.31
-1.8 0.47
...
x szereg(x)
-2 0.2
-1.9 0.3
-1.8 0.45
...
Zadanie 2.Zrobić program który policzy sumę liczb w podanym pliku.
Zadanie 3. Zrobić funkcję zamieniającą małe znaki na duże.
Funkcja powinna jako argument przyjmować wskaźnik na char.
Wczytać dowolny plik tekstowy (całość, do tablicy). Zmodyfikowany tekst wpisać do nowego
pliku, którego nazwą będzie aktualny czas ( time() ).
Zadanie 4. Zrobić funkcję która dla podanego argumentu x zwraca wartość funkcji sin i cos oraz x
przeliczone z radianów na stopnie.
Instrukcja
Argumenty programu:
#include <stdio.h>
#include <string.h>
// Pierwszy argument funkcji main – liczba argumentów programu
// Drugi argument – tablica łańcuchów tekstowych – argumentów
// Nazwy dowolne, przeważnie używane są argc i argv
int main(int argc, char *argv[])
{
int i;
for(i=0; i<argc; ++i)
{
printf("Argument %d: %s\n", i, argv[i]);
// strcmp – porównanie dwóch tekstów
// zwraca '0' jeśli są równe
if(strcmp(argv[i], "bla")==0)
printf("Argument %d to 'bla'\n", i);
}
return 0;
}
Uruchomienie: ./a.out tekst "dlugi tekst ze spacja" bla 32
Argumentem o indeksie 0 jest zawsze nazwa uruchomionego programu (nazwa pliku).
http://pl.wikibooks.org/wiki/C/strcmp
Otwarcie pliku:
#include <stdio.h>
int main(int argc, char *argv[])
{
// Sprawdz czy podana została ścieżka do pliku
if(argc<2)
{
printf("Podaj sciezke do pliku\n");
return 1;
}
// Zmienna przechowująca informacje o otwartym pliku
FILE *plik;
// Otworz plik do odczytu
plik=fopen(argv[1], "r");
// 'plik' jest równy 0 jeśli nie udało się otworzyć pliku
if(!plik)
{
printf("Plik %s nie istnieje\n", argv[1]);
return 2;
}
printf("Plik %s istnieje\n", argv[1]);
// Zamknij otwarty plik (ważne!)
fclose(plik);
return 0;
}
Funkcja fopen służy do otwarcia pliku. Pierwszym argumentem jest ścieżka do niego, drugi
informuje o tym, co z plikiem chcemy zrobić:
• "r" oznacza, że plik otwarty będzie do odczytu (read),
• "w" – zapis do pliku (write), plik zostanie nadpisany,
• "a" – dopisywanie (append).
Dodanie "b" po literce (np. "rb", "wb") oznacza, że plik traktowany będzie jako binarny (domyślnie
jest uznawany za tekstowy). Wszystkie funkcje do zapisu i odczytu do/z pliku działają na plikach
binarnych i tekstowych. Plik z tekstem może być otwarty w trybie binarnym. Otwarcie pliku w
trybie tekstowym może spowodować konwersje pewnych znaków (np. znaków końca linii).
Przeważnie otwarcie pliku w trybie binarnym jest bezpieczniejsze (stwierdzenie potwierdzone
doświadczeniem autora).
http://pl.wikibooks.org/wiki/C/Czytanie_i_pisanie_do_plik%C3%B3w
http://www.cplusplus.com/reference/cstdio/fopen/
Odczyt i zapis do pliku:
•
•
printf([format], [zmienne]) – wypisuje sformatowany tekst na ekran
fprintf([plik], [format], [zmienne]) – wypisuje sformatowany tekst do podanego pliku
•
•
scanf([format], [zmienne]) – wczytanie tekstu z konsoli i wpisane do zmiennej
fscanf([plik], [format], [zmienne]) – wczytanie tekstu z pliku i wpisanie do zmiennej
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
int i;
int tab[20];
// Otworz plik do odczytu
fp=fopen("plik.txt", "r");
// Wczytaj 20 liczb calkowitych z pliku
for(i=0; i<20; ++i)
fscanf(fp, "%d", &tab[i]);
// Zamknij plik
fclose(fp);
// Otworz plik do zapisu (binarnie)
fp=fopen("wyjscie.txt", "wb");
// Wpisz 20 liczb do pliku
for(i=0; i<20; ++i)
fprintf(fp, "%d ", tab[i]+1);
// Zamknij plik
fclose(fp);
return 0;
}
Odczyt i zapis binarny z pliku:
#include <stdio.h>
// Program kopiujący plik bajt po bajcie
int main(int argc, char *argv[])
{
FILE *in;
FILE *out;
if(argc<3)
{
printf("Uzycie: %s [plik do skopiowania] [sciezka]\n");
return 1;
}
in=fopen(argv[1], "rb");
out=fopen(argv[2], "wb");
while(1)
{
char c;
c=fgetc(in);
if(feof(in))
break;
putc(c, out);
printf("Przekopiowano %d bajtow\n", ftell(in));
}
fclose(in);
fclose(out);
return 0;
}
feof([plik]) – zwraca zero jeśli nie doszliśmy do końca pliku.
ftell([plik]) – zwraca pozycję w pliku (gdyby plik traktować jako tablicę, powie na którym indeksie
aktualnie jesteśmy).
http://www.cplusplus.com/reference/cstdio/ftell/
http://www.cplusplus.com/reference/cstdio/feof/
#include <stdio.h>
// Program zwracający wielkość podanych plików
int main(int argc, char *argv[])
{
FILE *fp;
int i;
int wielkosc;
for(i=0; i<argc; ++i)
{
fp=fopen(argv[i], "rb");
// Przeskocz na koniec pliku...
fseek(fp, 0, SEEK_END);
// Sprawdź w którym miejscu on jest...
wielkosc=ftell(fp);
// i wróć na początek, o ile chcesz odczytywać plik.
fseek(fp, 0, SEEK_SET);
printf("Plik %s zajmuje %d bajtow\n", argv[i], wielkosc);
fclose(fp);
}
return 0;
}
fseek([plik], [przesunięcie], [względem czego]) – przeskakuje na podane miejsce w pliku.
http://www.cplusplus.com/reference/cstdio/fseek/
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
int i;
int tab[20];
for(i=0; i<20; ++i) tab[i]=i;
// Otworz plik do odczytu (binarnie)
fp=fopen("plik.bin", "rb");
for(i=0; i<20; ++i)
// Wczytaj 1 element wielkości typu int
fread(&tab[i], sizeof(int), 1, fp);
// Zamiast używać pętli...
//fread(tab, sizeof(int), 20, fp);
// Zamknij plik
fclose(fp);
// Otworz plik do zapisu (binarnie)
fp=fopen("plik.bin", "wb");
// Wpisz 20 liczb do pliku
for(i=0; i<20; ++i)
{
++tab[i];
fwrite(&tab[i], sizeof(int), 1, fp);
}
// lub...
//fwrite(&tab[i], sizeof(int), 20, fp);
// Zamknij plik
fclose(fp);
return 0;
}
fread([adres zmiennej], [wielkość elementu w bajtach], [liczba elementów], [plik]) – wczytuje
podaną liczbę elementów o podanej wielkości pod podany adres.
sizeof([typ]) – zwraca ile bajtów zajmuje podany typ (sizeof(int) → 4, sizeof(char) → 1)
http://www.cplusplus.com/reference/cstdio/fread/
http://www.cplusplus.com/reference/cstdio/fwrite/
http://pl.wikibooks.org/wiki/C/Wska%C5%BAniki
Wskaźnik jest zmienną przechowującą adres z pamięci.
int *a;
Wskaźnik na zmienną typu int
char *tekst;
Wskaźnik na zmienną typu char
int **b;
Wskaźnik na zmienną typu int* (wskaźnik na
wskaźnik)
double ******c;
Wskaźnik na wskaźnik na wskaźnik na
wskaźnik...
int* (*wskaznik)(char*, int);
Wskaźnik na funkcję zwracającą wskaźnik na
int, przyjmującą argumenty typu char* oraz int
Nazwa tablicy jest wskaźnikiem na jej pierwszy element.
Nazwa funkcji jest wskaźnikiem na nią.
int *a;
Deklaracja zmiennej a będącej wskaźnikiem na
int
a=&zmienna;
Przypisanie adresu zmiennej zmienna do
wskaźnika a
*a;
Odczytanie wartości na którą wskazuje a.
a++;
Przestawienie a na następną zmienną w pamięci
a+=4;
Przeskoczenie 4 elementy wprzód.
#include <stdio.h>
int main(int argc, char *argv[])
{
int tablica[]={10, 11, 12};
int *wskaznik=tablica;
// ^ to samo co v
// int *wskaznik=&tablica[0];
int i;
// Zwieksz i o jeden, przesun wskaznik na następny element
for(i=0; i<3; i++, wskaznik++)
printf("%d\n", *wskaznik);
return 0;
}
Alokacja pamięci
Wskaźniki można wykorzystać do tworzenia tablic o różnych wartościach w trakcie działania
programu.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
double *wskaznik;
int i;
int liczba_elementow=50;
wskaznik=(double *) malloc(liczba_elementow * sizeof(double));
for(i=0; i<liczba_elementow; ++i)
wskaznik[i]=1.0/i;
// *(wskaznik+i)=1.0/i; // To samo co ^
for(i=0; i<liczba_elementow; ++i)
printf("%d: %f %f\n", i, wskaznik[i], *(wskaznik+i));
// Zajeta pamiec nalezy oddac przed koncem programu
// Tylko zli programisci tego nie robia
free(wskaznik);
return 0;
}
Funkcja malloc jako argument przyjmuje wielkość pamięci jaką potrzebujemy. Jeśli chcemy zrobić
tablicę na 50 elementów, każdy o wielkości 8 bajtów, potrzebujemy 50*8 bajtów.
sizeof(double) zwraca wielkość zmiennej typu double. sizeof(int), sizeof(char) zwrócą odpowiednio
wielkość zmiennej int i char.
Podpowiedzi
Zadanie 1. Zrobić program liczący wartość funkcji sin(x) przy pomocy rozwinięcia w szereg.
Zakres wartości x (od, do) oraz liczba przedziałów podawane będą jako argumenty programu,
wyniki wpisywane będą do plików – dokładny do pliku „sin_dokladny.txt”, obliczony z szeregu „sin_szereg.txt”.
Przykładowe wywołanie programu:
./a.out -2 4 60
^ Policzy dla x od -2 do 5, 60 podprzedziałów
Zadanie 2.Zrobić program który policzy sumę liczb w podanym pliku.
Zadanie 3. Zrobić dwie funkcje zamieniającą małe znaki na duże.
Funkcja powinna jako argument przyjmować wskaźnik na char.
Wczytać dowolny plik tekstowy (całość, do tablicy). Zmodyfikowany tekst wpisać do nowego
pliku, którego nazwą będzie aktualny czas ( time() ).
Zadanie 4. Zrobić funkcję która dla podanego argumentu x zwraca wartość funkcji sin i cos oraz x
przeliczone z radianów na stopnie.
Ad. 1 Argumenty programu są przechowywane jako tablice znaków. Aby zamienić tablicę znaków
na liczbę, można użyć funkcji sscanf albo atoi (jeśli chcemy zmienić na inta, atof – float).
Ad. 3 Zrobić funkcję:
void zamianaLiterki(char *tekst);
Na jej początku sprawdzić jakiej długości przesłany został tekst, przy pomocy funkcji strlen lub
wyliczając ręcznie:
int dlugosc=0;
while(tekst[dlugosc++]);
// ^ Kto zgadnie jak to dziala i czemu dziala?
printf("Dlugosc tekstu: %d\n", dlugosc);
Uruchomić pętlę zamieniającą znaki:
int i;
for(i=0; i<dlugosc; ++i)
{
if(literka jest mala)
zamien na duza
}
Aby cały plik wczytać za jednym razem, należy zrobić tablicę która go całego zmieści – potrzebna
jest więc wiedza o wielkości pliku. Przy pomocy fseek można przeskoczyć na koniec pliku, a przy
pomocy ftell można zobaczyć gdzie aktualnie jesteśmy. Będąc na końcu pliku, ftell zwróci jego
wielkość w bajtach.
Mając wielkość pliku, można zrobić tablicę i przy pomocy fread wczytać do niej cały plik.
int wielkosc;
char *dane;
FILE plik=fopen(...);
// Otworz plik
fseek(...);
wielkosc=ftell(...);
fseek(...);
// Przeskocz na koniec
// Sprawdz wielkosc pliku
// Wroc na poczatek
dane=(char *)malloc(...); // Zajmij pamiec
fread(...)
// Wczytaj caly plik do tablicy
Proponuję pamiętać o tym, że każdy tekst musi kończyć się znakiem '0'.
Po wczytaniu pliku, zrobić drugą tablicę tej samej wielkości i przekopiować do niej zawartość
pierwszej. Wywołać obie funkcji zmieniające znaki (do pierwszej przesłać wskaźnik na pierwszą
tablicę, do drugiej – na drugą).
Na koniec otworzyć dwa pliki i przy pomocy funkcji fwrite wpisać do nich zawartość każdej z
tablic.
Warto też przed końcem programu zwolnić zajętą pamięć.
Nazwę nowego pliku można utworzyć przy pomocy funkcji sprintf (działa jak printf, ale wpisuje do
tablicy zamiast na ekran).
Ad. 3 Chcemy zrobić funkcję, która zwraca trzy wartości wyliczone na podstawie jednego
argumentu. W C można zwrócić tylko jedną wartość, dlatego trzeba zrobić to inaczej: jako
argumenty funkcji przesłać wskaźniki na trzy dodatkowe zmienne, do których zostaną wpisane
obliczone wartości:
void sincosrad(float x, float *vsin, float *vcos, float *xdeg);
Przesłanie zmiennej 'normalnie' (float x) powoduje wysłanie do funkcji nowej zmiennej o tej samej
wartości (tzw. przesłanie argumentu przez wartość). Przesyłając wskaźnik podajemy funkcji adres
miejsca w pamięci do którego ma wpisać obliczone wartości.