Kurioses Verhalten



  • Hallo,

    ich habe mir ein kleines Programm geschrieben, um in einer Datei nach einer Zeile mit bestimmten Inhalt zu suchen und diese Zeile dann zu ersetzen.
    Um damit zB Konfigurationsdateien zu editieren.
    Aber darum gehts eigentlich gar nicht, denn das funktioniert auch.
    Ich benutze Ubuntu 11.10 und kompiliere das Programm ganz normal mit gcc.

    Hier mal der Code dazu, inklusive einer Datei die editiert werden soll:

    #include <stdio.h>
    #include <stdbool.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include <string.h>
    
    size_t countLines (FILE *file);
    bool readLines (char ***lines, size_t *lineCount, const char *filename);
    char * getLine (FILE *file);
    void freeLines (char ***lines, size_t lineCount);
    
    int main (int argc, char **argv)
    {
    	const char *filename = "example";
    	const char *background = "blork=";
    	const char *newbackground = "BLUB";
    	char **lines = 0;
    	size_t lineCount = 0;
    	int myLine = -1, i = 0;
    
    	printf ("##################################################################\n");
    
    	if (!readLines (&lines, &lineCount, filename))
    	{
    		printf ("error readLines\n");
    		return EXIT_FAILURE;
    	}
    
    	printf ("\n############################    2    #############################\n\n");
    
    	for (i = 0; i < lineCount; i++)
    	{
    		printf ("%02d: %s", i+1, lines[i]);
    	}
    
    	for (i = 0; i < lineCount; i++)
    	{
    		if(strstr (lines[i], background))
    			myLine = i;
    	}
    
    	size_t newL = (strlen (background) + strlen (newbackground) + 1) * sizeof (char);
    
    	lines[myLine] = realloc (lines[myLine], newL);
    	if (!lines[myLine])
    	{
    		printf ("error reallocating memory.\n");
    		return EXIT_FAILURE;
    	}
    
    	lines[myLine][0] = 0;
    	strcat (lines[myLine], background);
    	strcat (lines[myLine], newbackground);
    	strcat (lines[myLine], "\n");
    
    	printf ("\n############################    3    #############################\n\n");
    
    	for (i = 0; i < lineCount; i++)
    	{
    		printf ("%02d: %s", i+1, lines[i]);
    	}
    
    	return EXIT_SUCCESS;
    }
    
    size_t countLines (FILE *file)
    {
    	char ch;
    	size_t lineCount = 0;
    	long initialPos;
    
    	if (!file)
    		return 0;
    
    	initialPos = ftell (file);
    
    	while ( (ch = fgetc (file)) != EOF)
    	{
    		if (ch == '\n')
    			lineCount++;
    	}
    
    	fseek (file, initialPos, SEEK_SET);
    
    	return lineCount;
    }
    
    bool readLines (char ***lines, size_t *lineCount, const char *filename)
    {
    	FILE *file = fopen (filename, "r");
    
    	if (!file)
    		return false;
    
    	*lineCount = countLines (file);
    
    	*lines = (char **)calloc (*lineCount, sizeof (char*));
    
    	if (! (*lines) )
    		return false;
    
    	int i = 0;
    
    	printf ("\n############################    1    #############################\n\n");
    
    	while (i < *lineCount)
    	{
    		(*lines)[i++] = getLine (file);
    		printf ("%02d: %s", i, (*lines)[i-1]);
    	}
    
    	fclose (file);
    	return true;
    }
    
    char * getLine (FILE *file)
    {
    	long initialPos = 0;
    	size_t length = 0;
    	char ch, *buffer = NULL;
    
    	if (!file)
    		return 0;
    
    	initialPos = ftell (file);
    
    	while ( (ch = fgetc (file)) != EOF )
    	{
    		length++;
    
    		if (ch == '\n')
    		{
    			break;
    		}
    	}
    
    	if (!length)
    	{
    		return 0;
    	}
    
    	fseek (file, initialPos, SEEK_SET);
    	buffer = (char *)calloc (length, sizeof (char));
    	if (!buffer)
    	{
    		printf ("no buffer\n");
    		return 0;
    	}
    
    	fgets (buffer, length+1, file);
    
    	return buffer;
    }
    
    void freeLines (char ***lines, size_t lineCount)
    {
    
    }
    

    example:

    ksajflkdashfdaslkgf
    ksldafjlsdfjsdlkfajsdaskdf
    kmqawenm,a,dfks
    aksdfjlsadfnlasdfn
    ksladfylksdajfldasfnsd

    könasmdlfsadlkfnasdlf
    skaldfjlsdkjfdsl
    blork=tralalala
    saödlkjfaslkdfj

    sadöfjasdöfjka
    sdfklösdfjklösadfjsd
    aklfsj

    aksdflksdlkjdf!

    Mir ist etwas sehr seltsames dabei aufgefallen.
    Obwohl zwischen zwei Ausgaben 1 und 2 mMn NICHTS passiert, verändert sie sich.
    Hab das auch mit mehreren Dateien getestet, es wird teilweise einfach ein Zeichen nach dem "\n" in eine oder mehrere Zeilen eingefügt.

    Die Ausgabe schaut dann zB bei mir so aus:

    ##################################################################

    ############################ 1 #############################

    01: ksajflkdashfdaslkgf
    02: ksldafjlsdfjsdlkfajsdaskdf
    03: kmqawenm,a,dfks
    04: aksdfjlsadfnlasdfn
    05: ksladfylksdajfldasfnsd
    06:
    07: könasmdlfsadlkfnasdlf
    08: skaldfjlsdkjfdsl
    09: blork=tralalala
    10: saödlkjfaslkdfj
    11:
    12:
    13:
    14: sadöfjasdöfjka
    15: sdfklösdfjklösadfjsd
    16: aklfsj
    17:
    18: aksdflksdlkjdf!

    ############################ 2 #############################

    01: ksajflkdashfdaslkgf
    !02: ksldafjlsdfjsdlkfajsdaskdf
    03: kmqawenm,a,dfks
    04: aksdfjlsadfnlasdfn
    05: ksladfylksdajfldasfnsd
    06:
    07: könasmdlfsadlkfnasdlf
    08: skaldfjlsdkjfdsl
    09: blork=tralalala
    10: saödlkjfaslkdfj
    11:
    12:
    13:
    14: sadöfjasdöfjka
    15: sdfklösdfjklösadfjsd
    16: aklfsj
    17:
    18: aksdflksdlkjdf!

    ############################ 3 #############################

    01: ksajflkdashfdaslkgf
    !02: ksldafjlsdfjsdlkfajsdaskdf
    03: kmqawenm,a,dfks
    04: aksdfjlsadfnlasdfn
    05: ksladfylksdajfldasfnsd
    06:
    07: könasmdlfsadlkfnasdlf
    08: skaldfjlsdkjfdsl
    09: blork=BLUB
    10: saödlkjfaslkdfj
    11:
    12:
    13:
    14: sadöfjasdöfjka
    15: sdfklösdfjklösadfjsd
    16: aklfsj
    17:
    18: aksdflksdlkjdf!

    In Zeile 2 sieht man, dass in Zeile 1 noch ein Zeichen hinzugefügt wurde.
    Wäre ja jetzt blöd, das so in die Konfigurationsdatei zurückzuschreiben, weil sie dann korrupt wäre.
    Ich kann mir aber überhaupt nicht erklären, wieso das geschieht!

    Ich hoffe jemand weiß Rat,
    Danke schonmal.



  • Überprüfe doch mal ob du für deine Zeilen auch genug Speicher anforderst (auch für die '\0')

    BTW: sizeof(char) ist per Definition 1



  • DirkB schrieb:

    Überprüfe doch mal ob du für deine Zeilen auch genug Speicher anforderst (auch für die '\0')

    BTW: sizeof(char) ist per Definition 1

    Ich weiß. 😉

    Danke, das wars.
    Nur zum Verständnis, wieso wird dann jeweils etwas verscheidenes ausgegeben?
    In beiden Fällen wird doch auf den gleichen Speicherplatz zugegriffen.



  • Da wird einfach die '\0' überschrieben (für die du ja keinen Speicher hattest).



  • sacridex schrieb:

    Nur zum Verständnis, wieso wird dann jeweils etwas verscheidenes ausgegeben?
    In beiden Fällen wird doch auf den gleichen Speicherplatz zugegriffen.

    Wenn du nur 10 Byte anforderst und dort 11 Byte Daten reinpackst, landet das letzte Zeichen (in deinem Fall der Null-Terminator) in einem Speicherbereich, der dir nicht gehört. Diesen Speicher hält der Heap-Manager noch für frei und nutzt ihn bei weiteren malloc()-Aufrufen eventuell für Verwaltungsdaten.



  • Vielleicht findest du ja ein Muster, wenn du dir die Zeilenlängen anschaust.
    Es kann sein das malloc intern nur geradzahlige Speicherblöcke verwaltet.


Anmelden zum Antworten