Das mag am schönen Wetter liegen, der Kurs wird aber definitiv fortgesetzt. Es gibt noch mehrere Themen, die ich vorstellen möchte.
Die Suche ergab 238 Treffer
- 26.06.2023, 20:53
- Forum: Programmierung
- Thema: Fragen und Antworten zum C-Kurs
- Antworten: 108
- Zugriffe: 538628
- 26.06.2023, 20:48
- Forum: Programmierung
- Thema: Übungen zu "Programmieren in C mit dem z88dk"
- Antworten: 11
- Zugriffe: 57935
Re: Übungen zu "Programmieren in C mit dem z88dk"
Immerhin eine Lösung; die Verwendung der forms3-Bibliothek ist schon etwas für Fortgeschrittene.
Hier nun die Musterlösung mit der o.g. Eingabefunktion inputString:
Kompiliert wird mit
Hier nun die Musterlösung mit der o.g. Eingabefunktion inputString:
Kompiliert wird mit
Code: Alles auswählen
zcc +cpm -subtype=pcw80 lesson01.c -o lesson01.com
- 23.06.2023, 17:45
- Forum: Programmierung
- Thema: HP-GL Interpreter
- Antworten: 48
- Zugriffe: 253648
Re: noch neun Bilder
Das lässt sich schon machen, denke ich. Vielleicht auch noch weitere Optionen; es ist wohl vor allem eine Frage der Zeit.ein Thüringer hat geschrieben: ↑23.06.2023, 09:22 ...
Bernd, wird es eine Diashow-Funktion wie für VECREAD auch für PBMREAD geben?
...

- 27.05.2023, 19:54
- Forum: Programmierung
- Thema: Übungen zu "Programmieren in C mit dem z88dk"
- Antworten: 11
- Zugriffe: 57935
Re: Übungen zu "Programmieren in C mit dem z88dk"
Solltet ihr Schwierigkeiten haben die Eingabe benutzerfreundlich hinzubekommen, dann hilft euch vmtl. folgende Eingaberoutine:
Code: Alles auswählen
#include <stdio.h>
#include <conio.h>
#define CH_BEEP 7
#define CH_BACKSPACE 8
#define CH_RETURN 10
#define CH_AT 22
#define CH_SZ 126
#define CH_DEL_LEFT 127
/* Input a string with up to maxlen characters via keyboard.
Parameters: cp pointer to character buffer
maxlen maximum input length allowed
*/
void inputString(char *cp, int maxlen) {
char key;
char *ptrBuf;
int numChars;
ptrBuf = cp;
*ptrBuf = '\0'; // we start with an empty string
numChars = 0;
for (;;) {
key = getch();
if (key == CH_RETURN) { // finish input if <return> pressed
putchar('\n');
break;
}
if (numChars < maxlen) {
if (key > 31 && key < 126 || // regular characters
key > 90 && key < 94 || // uppercase Umlaut
key > 122 && key < 126 || // lowercase Umlaut
// key == CH_AT ||
key == CH_SZ)
{
putchar(key); // print character on screen
*ptrBuf++ = key; // write key to buffer
*ptrBuf = '\0'; // finalise string and point to the '\0' character
++numChars;
}
else {
if (key == CH_DEL_LEFT && *cp != '\0') { // delete left and characters available
putchar(CH_BACKSPACE); // move left
putchar(' '); // overwrite with blank
putchar(CH_BACKSPACE); // move left again
*--ptrBuf = '\0'; // shortens the string by 1 char
--numChars;
}
else {
putchar(CH_BEEP); // invalid key typed => beep
}
}
}
else {
putchar(CH_BEEP); // maximum number of characters reached => beep
}
}
}
- 06.05.2023, 18:07
- Forum: Programmierung
- Thema: Fragen und Antworten zum C-Kurs
- Antworten: 108
- Zugriffe: 538628
Re: Fragen und Antworten zum C-Kurs
Die Übungen zum C-Kurs werden in diesem Thema gesammelt. Auch eure Fragen und Lösungen sollen dort eingetragen werden. Nach einer gewissen Zeit werde ich eine Musterlösung anhängen.
Ich bin gespannt auf eure Mitarbeit!
Ich bin gespannt auf eure Mitarbeit!

- 06.05.2023, 18:03
- Forum: Programmierung
- Thema: Übungen zu "Programmieren in C mit dem z88dk"
- Antworten: 11
- Zugriffe: 57935
Übungen zu "Programmieren in C mit dem z88dk"
Übung 1
Der Benutzer soll die Adresse einer Person eingeben. Diese wird anschließend in einer Textdatei namens adressen.txt gespeichert. Nach dem Speichern erscheint eine Abfrage, ob eine weitere Adresse eingegeben werden soll. Wird die Abfrage bejaht, dann wird eine weitere Adresse eingegeben, die dann an die Textdatei adressen.txt angehängt wird. Wird sie verneint, dann wird das Programm beendet.
Einzugebende Felder:
Name
Vorname
Straße
PLZ
Wohnort
Telefon
E-Mail
Darstellung in der Textdatei (Beispiel):
Hugo Hirsch
Schloßallee 3
67118 Frankfurt
069 12345678
hugo.hirsch@pappnase.de
Der Benutzer soll die Adresse einer Person eingeben. Diese wird anschließend in einer Textdatei namens adressen.txt gespeichert. Nach dem Speichern erscheint eine Abfrage, ob eine weitere Adresse eingegeben werden soll. Wird die Abfrage bejaht, dann wird eine weitere Adresse eingegeben, die dann an die Textdatei adressen.txt angehängt wird. Wird sie verneint, dann wird das Programm beendet.
Einzugebende Felder:
Name
Vorname
Straße
PLZ
Wohnort
Telefon
Darstellung in der Textdatei (Beispiel):
Hugo Hirsch
Schloßallee 3
67118 Frankfurt
069 12345678
hugo.hirsch@pappnase.de
- 15.04.2023, 19:06
- Forum: Programmierung
- Thema: Programmieren in C mit dem z88dk
- Antworten: 20
- Zugriffe: 106253
16. Arbeiten mit Dateien 3
Diesmal wollen wir eine C-Quelldatei bearbeiten: die Zeilenkommentare mit dem doppelten Schrägstrich sollen in gewöhnliche C-Kommentare mit Schrägstrich-Stern am Anfang und Stern-Schrägstrich am Ende des Kommentars umgewandelt werden, denn nicht alle C-Compiler unterstützen die Zeilenkommentare. Wie können wir dabei vorgehen?
Wir benötigen zwei Dateien: die Originaldatei mit den Zeilenkommentaren und die umgewandelte, die nur noch normale Kommentaren enthält. Die Originaldatei öffnen wir zum Lesen, die Ausgabedatei zum Schreiben. Wir lesen die Originaldatei Zeile für Zeile ein. Dann suchen wir nach "//". Finden wir die beiden Schrägstriche, dann ersetzen wir die beiden Zeichen durch "/*"; danach suchen wir das Zeilenende und fügen davor ein "*/" ein. Finden wir die beiden Schrägstriche nicht, dann schreiben wir die Zeile unverändert in die Ausgabedatei.
Wir beginnen mit ein paar Variablen in der Funktion main():
Wir brauchen die beiden char-Arrays für die Dateinamen, die wir während der Programmausführung über die Tastatur eingeben werden. Wir sehen eine Länge von 20 Zeichen vor, was für CP/M-Dateinamen ausreicht. Dann brauchen wir noch zwei FILE pointer und einen Puffer für eine eingelesene Zeile. Der Puffer ist mit 512 Zeichen ausreichend groß bemessen, dass man gängige C-Programme damit bearbeiten können sollte. Natürlich ist C nicht formatgebunden, d.h. man könnte sogar ein komplettes C-Programm in eine einzige Zeile schreiben. Für solche Fälle ist unser Programm nicht ausgelegt; in der Praxis sollten Zeilen mit mehr als 512 Zeichen eher nicht vorkommen. Schließlich haben wir noch einen char pointer und eine Längen-Variable vom Typ size_t. Die Typdeklaration von size_t finden wir im include-Verzeichnis des Compilers unter sys/types.h: size_t entspricht hier einem unsigned int. Variablen dieses Typs können also Werte im Bereich von 0 bis 65535 annehmen.
Es folgt die Eingabe der Dateinamen und das Öffnen der Dateien:
Wenn eine der Dateien nicht geöffnet werden kann, z.B. weil wir einen ungültigen Dateinamen eingegeben haben, dann liefert fopen() den Wert NULL zurück und wir geben eine Fehlermeldung aus und beenden das Programm mit dem Fehlercode -1.
Wir lesen der Zeilen in einer while-Schleife ein:
Die bereits bekannte Funktion fgets() liest die Zeile in den Puffer buf ein und begrenzt das Einlesen sicherheitshalber auf die Größe des Puffers. Solange die Funktion einen Wert ungleich NULL zurückliefert, haben wir eine weitere Zeile einlesen können, die wir anschließend verarbeiten.
Zunächst ermitteln wir die Länge der Zeile:
Dann suchen wir den doppelten Schrägstrich mit der String-Funktion strstr(). Diese sucht in einem String nach dem Vorkommen eines Such-Strings. Wenn der Suchstring gefunden wird, dann liefert strstr() einen Pointer auf das erste gefundene Zeichen zurück, also den ersten Schrägstrich. Den wollen wir nicht verändern und inkrementieren den Pointer, damit er auf den zweiten Schrägstrich zeigt. Mit *cp = '*'; überschreiben wir den Schrägstrich mit einem Stern.
Jetzt müssen wir noch das Zeilenende finden um dort die Kommentarende-Kennung */ einzufügen.
Wir suchen das Newline-Zeichen mit der String-Funktion strchr(), da wir diesmal nur nach einem einzelnen Zeichen suchen wollen. Mit strstr() hätte man das auch machen können, allerdings wäre das weniger effizient.
Finden wir kein Newline-Zeichen, dann stimmt etwas ganz und gar nicht und wir steigen mit einer Fehlermeldung aus. Andernfalls überschreiben wir das Newline-Zeichen und die beiden folgenden Zeichen mit Leerzeichen, Stern und Schrägstricht, also " */". Damit zerstören wir das Zeilenende, das wir gleich aber wieder anhängen. Das tun wir in jedem Fall, also auch dann, wenn wir keinen doppelten Schrägstrich gefunden haben. Das ist nötig, weil fgets() nur das Newline-Zeichen einliest, nicht aber das Carriage-Return-Zeichen.
Vorher passen wir aber noch die Zeilenlänge an, die ja jetzt um drei eingefügte Zeichen angewachsen ist:
Jetzt schreiben wir das Zeilenende und das String-Abschlusszeichen in den Puffer und schreiben den Puffer mit der evtl. geänderte Zeile in die Ausgabedatei. Dazu verwenden wir die Funktion fwrite():
Am Ende, also nach der Schleife, müssen wir noch die beiden Dateien schließen und liefern den Fehlercode 0 an das Betriebssystem zurück.
In file_io_3.zip befindet sich das komplette Programm file3.c und eine Quelldatei mit Zeilenkommentaren zum Ausprobieren (pointer1.c).
Es sei noch anzumerken, dass das Programm in dieser Form noch nicht perfekt ist. Die Limitierung auf eine Zeilenlänge von max. 512 Zeichen (eigentlich noch etwas weniger wegen der Zeilenende- und Stringende-Zeichen) wurde bereits erwähnt. Außerdem erkennt das Programm nicht, wenn sich die doppelten Schrägstriche in einem String-Literal befinden, d.h. wenn im Code so etwas wie s = "abc // xyz"; vorkommt, dann würde hier der doppelte Schrägstrich fälschlicherweise als Kommentar erkannt. Selbiges gilt für doppelte Schrägstriche in Präprozessor-Direktiven. Natürlich kann man das Programm erweitern, damit es solche Fälle erkennt, aber das würde hier den Rahmen sprengen.
Wir benötigen zwei Dateien: die Originaldatei mit den Zeilenkommentaren und die umgewandelte, die nur noch normale Kommentaren enthält. Die Originaldatei öffnen wir zum Lesen, die Ausgabedatei zum Schreiben. Wir lesen die Originaldatei Zeile für Zeile ein. Dann suchen wir nach "//". Finden wir die beiden Schrägstriche, dann ersetzen wir die beiden Zeichen durch "/*"; danach suchen wir das Zeilenende und fügen davor ein "*/" ein. Finden wir die beiden Schrägstriche nicht, dann schreiben wir die Zeile unverändert in die Ausgabedatei.
Wir beginnen mit ein paar Variablen in der Funktion main():
Code: Alles auswählen
#include <stdio.h>
#include <string.h>
#define FILENAMELENGTH 20
#define BUFSIZE 512
/* Main
*/
int main(void) {
char filename[FILENAMELENGTH];
char filenameOut[FILENAMELENGTH];
FILE *fp;
FILE *fpOut;
char buf[BUFSIZE];
char *cp;
size_t len;
Es folgt die Eingabe der Dateinamen und das Öffnen der Dateien:
Code: Alles auswählen
printf("Zu konvertierende Datei: ");
scanf("%s", filename);
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Fehler: Datei %s nicht gefunden!\n", filename);
return -1;
}
printf("Ausgabedatei: ");
scanf("%s", filenameOut);
fpOut = fopen(filenameOut, "w");
if (fpOut == NULL) {
printf("Fehler: Konnte Ausgabedatei %s nicht oeffnen!\n", filenameOut);
fclose(fp);
return -1;
}
Wir lesen der Zeilen in einer while-Schleife ein:
Code: Alles auswählen
// Zeilen lesen
while (fgets(buf, sizeof buf, fp) != NULL) {
Zunächst ermitteln wir die Länge der Zeile:
Code: Alles auswählen
len = strlen(buf);
Code: Alles auswählen
// doppelten Schraegstrich suchen
cp = strstr(buf, "//");
if (cp != NULL) {
++cp; // zeigt jetzt auf den zweiten Schraegstrich
*cp = '*'; // "//" in "/*" umwandeln
Code: Alles auswählen
// Zeilenende suchen
cp = strchr(cp, '\n');
if (cp == NULL) {
printf("Oh - das sollte nicht passieren: Zeilenende nicht gefunden!\n");
return -1;
}
// Zeilenende mit " */" ueberschreiben
*cp++ = ' ';
*cp++ = '*';
*cp = '/';
Finden wir kein Newline-Zeichen, dann stimmt etwas ganz und gar nicht und wir steigen mit einer Fehlermeldung aus. Andernfalls überschreiben wir das Newline-Zeichen und die beiden folgenden Zeichen mit Leerzeichen, Stern und Schrägstricht, also " */". Damit zerstören wir das Zeilenende, das wir gleich aber wieder anhängen. Das tun wir in jedem Fall, also auch dann, wenn wir keinen doppelten Schrägstrich gefunden haben. Das ist nötig, weil fgets() nur das Newline-Zeichen einliest, nicht aber das Carriage-Return-Zeichen.
Vorher passen wir aber noch die Zeilenlänge an, die ja jetzt um drei eingefügte Zeichen angewachsen ist:
Code: Alles auswählen
// Laenge anpassen: wir haben jetzt 3 Zeichen mehr
len += 3;
}
Code: Alles auswählen
// CR, LF und String-Abschluss
buf[--len] = '\r';
buf[++len] = '\n';
buf[++len] = '\0';
// Zeile schreiben
fwrite(buf, 1, len, fpOut);
Code: Alles auswählen
}
fclose(fp);
fclose(fpOut);
return 0;
}
Es sei noch anzumerken, dass das Programm in dieser Form noch nicht perfekt ist. Die Limitierung auf eine Zeilenlänge von max. 512 Zeichen (eigentlich noch etwas weniger wegen der Zeilenende- und Stringende-Zeichen) wurde bereits erwähnt. Außerdem erkennt das Programm nicht, wenn sich die doppelten Schrägstriche in einem String-Literal befinden, d.h. wenn im Code so etwas wie s = "abc // xyz"; vorkommt, dann würde hier der doppelte Schrägstrich fälschlicherweise als Kommentar erkannt. Selbiges gilt für doppelte Schrägstriche in Präprozessor-Direktiven. Natürlich kann man das Programm erweitern, damit es solche Fälle erkennt, aber das würde hier den Rahmen sprengen.
- 07.04.2023, 10:41
- Forum: Programmierung
- Thema: Fragen und Antworten zum C-Kurs
- Antworten: 108
- Zugriffe: 538628
Re: Fragen und Antworten zum C-Kurs
In Kapitel 10.2 habe ich geschrieben, dass der Name eines Arrays auch ein Pointer ist. buf ist also nicht der Wert des Arrays mit all seinen 100 Characters, sondern der Pointer, der auf den ersten Character zeigt. buf ist also eine Adresse, nicht der ganze Array. Beim Aufruf einer Funktion mit buf als Parameter wird also nicht der ganze Buffer kopiert, sondern nur die zwei Bytes des Zeigers.Paul hat geschrieben: ↑07.04.2023, 09:52 ...
Was geschieht mit buf? Wird beim Aufruf der gesamte Buffer kopiert? Das wäre dann ja vergleichsweise langsam, erklärt aber warum der buf vom main nicht verändert werden kann.
Ist es dann sinnvoll die resultierende Variable mit dem gleichen Namen zu versehen? Intuitiv hätte ich lbuf verwendet was eine lokale Kopie von buf andeutet.
Es wird die Adresse des Arrays übergeben, keine Kopie. Die Änderungen mit *start=... in parseToken ändern den Inhalt des Arrays buf in main.
Diese Fragen sollten mit o.g. Erklärungen beantwortet sein.Paul hat geschrieben: ↑07.04.2023, 09:52 du veränderst start, was erstmal keine Auswirkung hat weil es ja eine lokale Kopie ist. Am ende erhöhst du noch start um eins und gibst es als rückgabewert zurück.
Spannender wird es mit field. Das veränderst du und gibst am ende noch das Stringende Zeichen hinzu. Aber ist es nicht genau wie start eine lokale Kopie?
Delimiter wird nicht verändert, also stellt sich auch keine Frage bezüglich der Auswirkung auf die aufrufende Parseline.
- 07.04.2023, 10:30
- Forum: Programmierung
- Thema: Fragen und Antworten zum C-Kurs
- Antworten: 108
- Zugriffe: 538628
Re: Fragen und Antworten zum C-Kurs
Ja, man könnte auch 255 verwenden. Oder 2000. Wenn man mit festen Feldgrößen arbeitet, muss man immer überlegen, wie groß der zu speichernde Inhalt eigentlich sein kann. Der Buffer muss groß genug sein, damit die längste Zeile hineinpasst, oder man muss vorsehen eine Zeile in mehreren Etappen einzulesen, wie du das nennst. Das macht das Einlesen komplizierter, weil man im ersten Anlauf nicht alle Felder bekommt und Felder über zwei Lesevorgänge geteilt sein können.
Ist die maximale Länge einer Zeile bekannt, z.B. weil man weiß, aus welcher Quelle die CSV-Datei stammt, dann kann man den Buffer entsprechend dimensionieren. Man muss aber beachten, dass man auch Platz für den Zeilenumbruch und das String-Ende-Zeichen vorsieht.
Die 60 und die 50 sind zusammen zwar mehr als jede Zeile lang ist, aber wir haben ja viele Zeilen, und so kann in einer Staat besonders lang sein und in einer anderen die Stadt. Man muss jeweils genug Platz für das längste Feld reservieren.
- 31.03.2023, 13:53
- Forum: Programmierung
- Thema: Fragen und Antworten zum C-Kurs
- Antworten: 108
- Zugriffe: 538628
Re: Fragen und Antworten zum C-Kurs
Ja, Kurt, da gibt's noch so einiges...
Was ist denn mit schombi? Ist der noch dabei?

Was ist denn mit schombi? Ist der noch dabei?