Forum: Compiler & IDEs strncpy und globaler String: Verständnisfragen


von Bernhard N. (bernieserver)


Lesenswert?

Hi,

ich brauche Euch wieder einmal.

Ich habe folgenden Quelltext zum Üben in Visual Studio geschrieben. 
Später wird ein ähnlicher Code in einem Atmel ATMega32 Platz finden.

Folgendes soll geschenen, was laut meines Wissens über C aber nicht 
funktionieren sollte:

In das leere globale Char Array gStr[] soll mit strncpy ein mittels 
einer Funktion übergebenen Zeigers das Array hineinkopiert werden und 
später ausgegeben werden. Nun frgae ich mich: Ein globales Array wird ja 
mit einer festen Größe erzeugt. Wenn man jetzt das Array mittels strncpy 
quasi vergrößert werden da nicht der Stack oder der Datenbereich 
teilweise überschrieben? Warum also wird das int i = 123 nicht 
überschrieben bzw. warum gibt der Compiler keine Warnungen oder 
Fehlermeldungen aus? Ich erzeuge ja nichts mit malloc aufm Heap?
Habe ich da einen Denkfehler?
Compileroptimierungen?

Hilft mir bitte mal ;)
1
#include <stdio.h>
2
#include <string.h>
3
4
char gStr[] = "";
5
int i = 123;
6
7
void kopieren(unsigned char ZuVergleichen[],int size){
8
  strncpy(gStr,ZuVergleichen,size);
9
}
10
11
int main()
12
{
13
  unsigned char myString[] = "Burny";
14
  kopieren(myString,sizeof(myString));
15
  printf("%s\n",gStr);
16
  printf("%d\n",i);
17
  getchar();
18
  return 0;
19
}


Gruß

Bernhard

von Karl H. (kbuchegg)


Lesenswert?

Bernhard N. schrieb:

> später ausgegeben werden. Nun frgae ich mich: Ein globales Array wird ja
> mit einer festen Größe erzeugt. Wenn man jetzt das Array mittels strncpy
> quasi vergrößert

Da wird nichts vergrößert.
Wenn du das Array mit sagen wir mal 10 Zeichen definierst und strncpy 
den Auftrag gibst, dort 20 Zeichen abzulegen, dann wird strncpy zwar in 
das Array schreiben (die ersten 10 Zeichen) aber auch Speicher 
beschreiben, der nicht zum Array gehört.

Es ist einzig und alleine dein Bier dafür zu sorgen, dass so etwas nicht 
passiert. Keine str... Funktion nimmt dir diese Verantwortung ab.

von Rene H. (Gast)


Lesenswert?

Doch strdup allociert Speicher.

von Karl H. (kbuchegg)


Lesenswert?

Bernhard N. schrieb:

> teilweise überschrieben? Warum also wird das int i = 123 nicht
> überschrieben bzw.

Weil es von den Details abhängt, wie der Compiler die Dinge im Speicher 
anordnet.
Probier mal

int j = 567;
char gStr[] = "";
int i = 123;

also eine Variable davor und eine danach. Meistens ist es so, dass eine 
der beiden danach Schrott enthält weil der Compiler die Variablen ja 
auch nicht irgendwie willkürlich im Speicher anordnet, sondern eine 
bestimmte Reihenfolge einhält.

Genau das bedeutet: undefined behaviour
Alles mögliche kann passieren. Inklusive "sieht so aus als ob es geht". 
Aber ein Fehler, den man nicht sieht ist immer noch ein Fehler.

> warum gibt der Compiler keine Warnungen oder
> Fehlermeldungen aus?

Da müsste er ständig warnen. Der Compiler weiß ja nicht, wie groß der 
String ist, den du ins Array kopieren willst.

(OK. Mit einer aufwändigen Analyse könnte er das IN DEINEM FALL 
rausfinden. Aber im Allgemeinen geht das nicht. Array und Funktion die 
das Array beschreibt müssen ja nicht in derselben Compilation Unit sein)

von Rene H. (Gast)


Lesenswert?

Du kannst einen globalen Pointer nehmen und mit strndup() statt 
strncpy() kopieren. Allerdings ist dann das freigeben des Speichers in 
Deiner Verantwortung (wird oft vergessen).

von Karl H. (kbuchegg)


Lesenswert?

Rene H. schrieb:
> Doch strdup allociert Speicher.

OK.
Mit Ausnahme von strdup kümmert sich keine einzige str... Funktion 
darum, ob zu beschriebende Speicherbereiche gross genug sind.

Aus dem ganz simplen Grund, weil man in C aus einem Pointer nicht 
ablesen kann, wie gross der Speicher ist auf den er zeigt. Und die 
strn... Funktionen kann man ja auch anlügen ohne dass sie es merken.

von Rene H. (Gast)


Lesenswert?

Der Compiler macht Dich auf "Speicher-Sauereien" nicht aufmerksam. Das 
liegt in der Hand des Programmierers im und mit dem Speicher zu denken.
Hast Du da etwas falsch gemacht, stürzt Deine Software nicht 
deterministisch ab.

von Bernhard N. (bernieserver)


Lesenswert?

Wow, was für eine Antwort Flut. Danke erstmal an Alle, auch den Tipp mit 
strdup, kannte ich noch nicht. Speicher freimachen mache ich dann 
natürlich.

Ich spiele mal weiter mit dem Beispielcode herum.

Gruß

Bernhard N.

von Karl H. (kbuchegg)


Lesenswert?

Bernhard N. schrieb:
> Wow, was für eine Antwort Flut. Danke erstmal an Alle, auch den Tipp mit
> strdup, kannte ich noch nicht. Speicher freimachen mache ich dann
> natürlich.

Das sagst du jetzt so :-)

von Bernhard N. (bernieserver)


Lesenswert?

Karl heinz Buchegger schrieb:
> Bernhard N. schrieb:
>> Wow, was für eine Antwort Flut. Danke erstmal an Alle, auch den Tipp mit
>> strdup, kannte ich noch nicht. Speicher freimachen mache ich dann
>> natürlich.
>
> Das sagst du jetzt so :-)

Gib mir ein free() und ich bau das dann ein. Dann vergesse ich es nicht 
^^

von Karl H. (kbuchegg)


Lesenswert?

Bernhard N. schrieb:
> Karl heinz Buchegger schrieb:
>> Bernhard N. schrieb:
>>> Wow, was für eine Antwort Flut. Danke erstmal an Alle, auch den Tipp mit
>>> strdup, kannte ich noch nicht. Speicher freimachen mache ich dann
>>> natürlich.
>>
>> Das sagst du jetzt so :-)
>
> Gib mir ein free() und ich bau das dann ein. Dann vergesse ich es nicht
> ^^


:-) Wenns nur in der Praxis so einfach wäre :-)


(vereinfachter Code, der so simpel in einem realen Programm nicht 
auftaucht. Wenn sowas passiert, dann immer in der verschärften Version, 
verteilt auf 8 Funktionen in 6 Files über 12 Bildschirmseiten :-)
1
   char* tmp = "abcdef";
2
3
   if( i == 5 )
4
     tmp = strdup( somestring );
5
6
   ..... some operations
7
8
   // to free or not to free, that is the question
9
 }

von Bernhard N. (bernieserver)


Lesenswert?

hehe, ja wirkt etwas gekünstelt.
Aber raub mir doch nicht einfach die Illusion, dass das Programmieren 
hier so viel Frust erzeugen kann. Ich will mir mein naives Weltbild 
nicht so einfach zerstören. ^^

Gruß

Bernhard

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.