{
void *temp;
/* Sortowanie numerycznie i leksykograficznie */
temp=v[i];
#include <stdio.h>
v[i]=v[j];
#include <string.h>
v[j]=temp;
}
#define MAXLINES 5000 /* maksymalna liczba wierszy do sortowania */
#define MAXLEN 1000 /* dlugosc wiersza wejsciowego */
char *lineptr[MAXLINES];
/* wskazniki do wierszy
int getline(char *, int);
tekstu */
/* readlines: wczytaj wiersze z wejscia */
int readlines(char *lineptr[], int nlines); int readlines(char *lineptr[], int maxlines) void writelines(char *lineptr[], int nlines);
{
int len, nlines=0;
void qqsort(void *lineptr[], int left, int right, char *p, line[MAXLEN];
int (*comp)(void *, void *));
int numcmp(const char *, const char *);
while ((len=getline(line, MAXLEN)) > 0) if (nlines >= maxlines || (p=(char *)
/* uporzadkuj wiersze z wejscia */
malloc(len))==NULL)
main(int argc, char *argv[])
return -1;
{
else {
int nlines; /* liczba wszystkich wierszy */
line[len-1]=’\0’; /* usun znak nowego wiersza */
int numeric=0; /* 1 - jesli sortowanie numeryczne */
strcpy(p,line);
lineptr[nlines++]=p;
if (argc > 1 && strcmp(argv[1], "-n") == 0)
}
numeric=1;
return nlines;
if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
}
qqsort((void **) lineptr, 0, nlines-1,
(int (*) (void *, void *))
/* writelines: wypisz wiersze na wyjscie */
(numeric ? numcmp : strcmp));
void writelines(char *lineptr[], int nlines) writelines(lineptr, nlines);
{
return 0;
int i;
} else {
for (i=0; i < nlines; i++)
printf("za duzo wierszy do sortowania\n"); printf("%s\n", lineptr[i]);
return 1;
}
}
}
/* getline: wczytaj wiersz do s, podaj jego dlugosc */
int getline(char s[], int lim)
/* qsort: uporzadkuj v[left] ... v[right] rosnaco */
{
void qqsort(void *v[], int left, int right, int c,i;
int (*comp)(void *, void *))
for (i=0; i<lim -1 && (c=getchar()) != EOF
{
&& c != ’\n’; ++i)
int i,last;
s[i]=c;
void swap(void *v[], int, int);
if (c==’\n’)
if (left >= right) /* nic nie rob, jesli tablica*/
s[i]=c;
return;
/* zawiera mniej niz dwa elementy */
else
swap(v, left, (left+right)/2);
++i;
last=left;
s[i]=’\0’;
for (i=left+1; i<=right; i++)
return i;
if ((*comp)(v[i],v[left]) < 0)
}
swap(v, ++last, i);
swap(v, left, last);
qqsort(v, left, last-1, comp);
Argumenty wskaźnikowe typu void *
qqsort(v, last+1, right, comp);
}
Funkcja qqsort ma argumenty typu void * dla argumentów wskaźnikowych. Za pomoc¸
a operacji rzutowania można dowolny
#include <stdlib.h>
wskaźnik przkeształcić do typu void * i z powrotem bez utraty informacji.
/* numcmp: porownaj numerycznie s1 i s2 */
int numcmp(const char *s1, const char *s2) Deklaracja
{
double v1,v2;
int (*comp) (void *, void *)
v1=atof(s1);
v2=atof(s2);
deklaruje wskaźnik do funkcji zwracaj¸
acej wartość całkowit¸
a.
if (v1 < v2)
Natomiast
return -1;
else if (v1 > v2)
return 1;
int *comp(void *, void *)
else
return 0;
}
mówi, że comp jest funkcj¸
a zwracaj¸
ac¸
a wskaźnik do obiektów
całkowitych.
Skomplikowane deklaracje
void swap(void *v[], int i, int j)
Przykłady:
argv: wskaźnik do wskaźnik do char
return tokentype = BRACKETS;
int (*daytab)[13]
daytab: wskaźnik do tablica[13] o
} else if (isalpha(c)) {
elementach int
int *daytab[13]
daytab: tablica[13] o elementach
for (*p++ = c; isalnum(c=getch()); )
wskaźnik do int
*p++=c;
void *comp()
comp: funkcja zwracaj¸
aca wskaź-
*p=’\0’;
nik do void
ungetch(c);
void (*comp)()
comp: wskaźnik do funkcja zwra-
return tokentype = NAME;
caj¸
aca void
char (*(*x())[])()
x: funkcja zwracaj¸
aca wskaźnik do
} else
tablica[] o elementach wskaźnik do
return tokentype = c;
funkcja zwracaj¸
aca char
}
char (*(*x[3])())[5]
x: tablica[3] o elementach wskaź-
nik do funkcja zwracaj¸
aca wskaź-
#define BUFSIZE 100
/* maks. rozmiar bufora */
nik do tablica[5] o elementach char
char buf[BUFSIZE];
/* bufor na zwroty z ungetch */
Uproszczona postać reguł skaładniowych gramatyki wprowa-int bufp=0;
/* nastepne wolne miejsce w buforze */
dzaj¸
acej deklaratory:
int getch(void) /* wez znak, byc moze oddany na */
deklarator:
{
/*
wejscie */
opcjonalne * bezposredni-deklarator
return (bufp > 0) ? buf[--bufp]:getchar();
}
bezposredni-deklarator:
nazwa
void ungetch(int c) /* oddaj znak z powrotem na */
(deklarator)
{
/*
wejscie */
bezposredni-deklarator()
if (bufp >= BUFSIZE)
bezposredni-deklarator[opcjonalny rozmiar]
printf("ungetch: za wiele zwrotow\n"); else
buf[bufp++]=c;
}
Przykład (program rozszyfrowuj¸
acy proste deklaracje):
#include <stdio.h>
/* dcl: analiza skladniowa deklaratora */
#include <string.h>
void dcl(void)
#include <ctype.h>
{
#define MAXTOKEN 100
int ns;
for (ns=0; gettoken()==’*’;) /* zlicza *-i */
enum ( NAME, PARENS, BRACKETS };
ns++;
dirdcl();
void dcl(void);
while (ns-- > 0)
void dirdcl(void);
strcat(out, "wskaznik do");
int gettoken(void);
}
int tokentype;
/* typ ostatniego elementu
*/
char token[MAXTOKEN]; /* tekst ostatniego elementu */
/* dirdcl: analiza skladniowa bezposredniego char name[MAXTOKEN];
/* nazwa wystepujaca w dekl. */
deklaratora */
char datatype[MAXTOKEN]; /*typ danych: char,int,itp.*/
void dirdcl(void)
char out[1000];
/* wyjsciowy opis slowny */
{
int type;
main()
/* dcl: zamien deklaracje C na opis slowny */
if (tokentype == ’(’) {
/* (deklarator) */
{
dcl();
while (gettoken() != EOF) {/* pierwszy leksem w */
if (tokentype != ’)’)
strcpy(datatype, token)
/* wierszu jest typem*/
printf("blad: brak nawiasu )\n"); out[0]=’\0’;
/* danych */
} else if (tokentype == NAME) /* nazwa zmiennej */
dcl();
/* analiza skladniowa reszty wiersza */
strcpy(name, token);
if (tokentype != ’\n’)
else
printf("blad skladniowy\n");
printf("blad: spodziewana nazwa lub"
printf("%s: %s %s\n", name, out, datatype);
" (deklarator)\n");
}
while (type=gettoken())==PARENS || type==BRACKETS) return 0;
if (type == PARENS)
/* para nawiasow () */
}
strcat(out,"funkcja zwracajaca"); else {
/* para nawiasow [] */
int gettoken(void) /* podaj nastepny leksem */
strcat(out, " tablica");
{
strcat(out,token);
/* ew. rozmiar */
int c, getch(void);
strcat(out," o elementach");
void ungetch(int );
}
}
while ((c=getch()) == ’ ’ || c == ’\t’)
;
if (c == ’(’) {
if ((c=getch()) == ’)’) {
Zmienna długość list argumentów
strcpy(token, "()");
return tokentype = PARENS;
} else {
#include <stdio.h>
ungetch(c);
#include <stdarg.h>
return tokentype = ’(’;
/* minprintf: minimalna printf ze zmienna
}
liczba argumentow */
} else if (c == ’[’) {
void minprintf(char *fmt, ... )
for (*p++ = c; (*p++ = getch()) != ’)’;)
{
;
va_list ap; /* wskazuje po kolei kazdy nienazwany*/
*p=’\0’;
char *p, *sval;
/*
argument */
double dval;
va_start(ap, fmt); /* ap wskazuje pierwszy nienazwany argument;
fmt - ostatni nazwany argument */
for (p=fmt; *p; p++) {
if (*p != ’%’) {
putchar(*p);
continue;
}
switch(*++p) {
case ’d’:
ival = va_arg(ap, int);
printf("%d",ival);
break;
case ’f’:
dval=va_arg(ap, double);
printf("%f",dval);
break;
case ’s’:
for (sval=va_arg(ap, char *); *sval; sval++) putchar(*sval);
break;
default:
putchar(*p);
break;
}
}
va_end(ap); /* po pracy wyczysc po sobie */
}
Trzy makra zdefiniowane w <stdarg.h>: va_start(va_list ap, lastfix);
type va_arg(va_list ap, type);
void va_end(va_list ap);
va_list
-
tablica, ktora przechowuje informacje
potrzebne dla va_arg i va_end
va_arg i va_start zapewniaj¸
a przenaszalny sposób dost¸
epu do
zmiennych list argumentów.
• va_start ustawia wskaźnik do pierwszego nienazwanego argumentu przekazanego do funkcji
• va_arg rozszerza si¸e do wyrażenia maj¸acego ten sam typ i wartość jak nast¸
epny przekazany argument
• va_end pomaga funkcji wykonać normalny powrót Przykład (sumowanie liczb):
#include <stdio.h>
#include <stdarg.h>
/* calculate sum of a 0 terminated list */
void sum(char *msg, ...)
{
int total = 0;
va_list ap;
int arg;
va_start(ap, msg);
while ((arg = va_arg(ap,int)) != 0) {
total += arg;
}
printf(msg, total);
va_end(ap);
}
int main(void) {
sum("The total of 1+2+3+4 is %d\n", 1,2,3,4,0); return 0;
}