Hallo Vitali !
Der grundsätzliche Fehler liegt, denke ich, darin, dass ich
char *buff[2] verwende. Fälschlicherweise ging ich davon aus,
dass ich in diesem Array 2 Zeichenketten speichern könnte. Es
ist aber so, dass ich hier lediglich eine Zeichenkette von 2
Zeichen speichern kann. Richtig?
Nein.
char *buff[2] heisst du hast ein Array mit 2 Elementen die jeweils einen Pointer auf einen String (eigentlich auf einen Character der das erste Zeichen des Strings ist) enthalten.
Diese Pointer musst du erst initialisieren indem du sie auf einen Speicherbereich zeigen lässt der den String enthalten soll.
z.B.
buff[0] = "Das ist ein String";
Der Pointer in buff[0] zeigt jetzt auf den angegebenen String den der Compiler im Speicher angelegt hat.
buff[1] = (char\*)malloc(sizeof(char) \* (MAXCHARS + 1));
Der Pointer in buff[1] zeigt jetzt auf einen Speicherbereich der mittels malloc() angelegt wurde und Platz für MAXCHARS Characters plus ein ‚\0‘ hat.
(sizeof(char) ist eigentlich überflüssig weil char praktisch immer die Grösse 1 hat, aber so ist man auch auf Fälle wo das nicht der Fall ist vorbereitet)
Um es etwas einfacher zu halten habe ich ein Array char
*buff[8] definiert in den ich nacheinander alles schreiben
werde.
Das ist jetzt ein Array mit 8 Elementen die jeweils einen Pointer auf einen String enthalten. Diese Pointer sind nicht initialisiert und zeigen irgendwohin in die Wildnis !
Danach initialisiere ich das iov-Array:
iov[0].iov_base=buff[0];
iov[0].iov_len=3;
iov[1].iov_base=buff[4];
iov[1].iov_len=3;
iov[0].iov_base zeigt jetzt irgendwohin weil buff[0] nicht initialisiert war !
Und daraufhin versuche ich auf die jeweils letzte Stelle,
buff[4] und buff[8] ein „\0“ zu schreiben:
buff[3]="\0";
buff[7]="\0";
Du schreibts jetzt in buff[3] und buff[7] einen Pointer auf jeweils einen String der nur aus dem Zeichen ‚\0‘ besteht.
Beachte den Unterschied:
buff[3] = "\0";
ist zwar korrekt, weil „\0“ ein String ist den der Compiler im Speicher angelegt hat und dessen Adresse er dann in buff[3] schreibt.
Du wolltest aber wohl
buff[3] = '\0';
schreiben, also an die Stelle buff[3] das Zeichen ‚\0‘, was aber zu einem Compilerfehler geführt hätte weil buff ja kein Array von Charactern ist sonder ein Array von Pointern auf Character !
Auslesen des Buffers mit:
printf(„Inhalt buff[0]: %s\n“,buff[0]);
printf(„Inhalt buff[3]: %s\n“,buff[4]);
readv() gibt mir zurück, dass 6 Byte gelesen wurden. Das ist
korrrekt.
(Habe die rel.txt auch vereinfacht und alles in eine Zeile
geschrieben: hhhvvv)
Aber das erste printf() gibt nicht nur die Zeichen bis zum
„\0“ aus, sondern alles was scheinbar im buff[] steckt:
ubuntu@ubuntu:~/Desktop$ ./llio4.o
File descriptor Nr.: 3
Mit readv() gelesen: 6 Bytes
Inhalt buff[0]: hhh�I��l�
Segmentation fault (core dumped)
Nein, das ist ein Irrtum.
Weil buff[0] nie initialisiert wurde zeigt der Pointer in buff[0] irgendwohin, ebenso wie alle anderen ausser buff[3] unf buff[7].
readv() hat jetzt Daten in Speicherbereiche gelesen die zufällig irgendwo stehen, ein Zufall dass nicht bereits da der Fehler auftrat.
Da beim ersten printf() das gesamte Array ausgegeben wurde,
greift er beim zweiten printf() wie es scheint in fremden
Specherbereich und scheitert.
Nein, beim printf von buff[0] wird alles ab der Stelle ausgegeben auf die buff[0] zeigt, dass ist das was readv gelesen hat und alles danach bis zum ersten ‚\0‘ das es zufällig findet (das von dir geschriebene buff[3] = „\0“ hat ja überhaupt nichts mit buff[0] zu tun), dabei kam es dann wohl auch schon zum Speicherüberlauf (Segmentation fault)
Du musst bei der Definition von Arrays darauf achten was du da definierst:
char buff[8];
erzeugt ein Array von Characters der Länge 8
char buff[2][4];
(in der Art wie in der Antwort von Marvin weiter oben) erzeugt ein zweidimensionales Array von 2 * 4 Characters. Man kann dies gleich wie ein lineares Array von 8 Characters behandeln, das kann bei manchen Compilern aber auch schiefgehen.
char \*buff[2];
erzeugt dagegen ein Array der Länge 2 aus Pointern auf Character !
Mir scheint, du wolltest statt dem Array auf Strings einen String direkt verwenden, das hätte dann so aussehen müssen:
char buff[8];
dann weiter unten
iov[0].iov\_base = &(buff[0]);
iov[0].iov\_base = &(buff[4]);
also die Adressen von buff[0] und buff[4];
desweiteren
buff[3] = '\0';
buff[7] = '\0';
printf("Inhalt buff[0]: %s\n", &(buff[0]));
(oder einfach
printf("Inhalt buff[0]: %s\n", buff));
)
printf("Inhalt buff[4]: %s\n", &(buff[4]));
Die alternative Lösung wäre natürlich wirklich mehrere Buffer zu verwenden:
#include "stdio.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/uio.h"
#include "fcntl.h"
#include "string.h"
#define MAXCHARS 3
int main(){
struct iovec iov[2];
int nr, fd, i;
char \*buff[2];
buff[0] = (char\*)malloc(sizeof(char) \* MAXCHARS + 1); // MAXCHARS + ein '\0'
buff[1] = (char\*)malloc(sizeof(char) \* MAXCHARS + 1); // MAXCHARS + ein '\0'
memset(buff[0], 0, sizeof(char) \* MAXCHARS + 1); // mit 0-en initialisieren, nach dem letzen eingelesenen Zeichen kommt dann sicher ein '\0' (sofern max. MAXCHARS Zeichen gelesen wurden)
memset(buff[1], 0, sizeof(char) \* MAXCHARS + 1); // mit 0-en initialisieren, nach dem letzen eingelesenen Zeichen kommt dann sicher ein '\0' (sofern max. MAXCHARS Zeichen gelesen wurden)
fd=open("ler.txt", O\_RDONLY);
printf("File descriptor Nr.: %i\n", fd);
iov[0].iov\_base = buff[0];
iov[0].iov\_len = MAXCHARS;
iov[1].iov\_base = buff[1];
iov[1].iov\_len=MAXCHARS;
nr=readv(fd, iov, 2);
close(fd);
printf("Mit readv() gelesen: %d Bytes\n",nr);
printf("Inhalt buff[0]: %s\n",buff[0]);
printf("Inhalt buff[4]: %s\n",buff[4]);
}
mfg
Christof