Forum: Compiler & IDEs Warum funktioniert 1 String unbekannter Länge so nicht?


von Maria (Gast)


Lesenswert?

Tag zusammen

So geht es:
unsigned char  CRCText[8];
CRCText = "CRC-Test";

Aber warum kann ich einen String unbekannter Länge so nicht deklarieren?

unsigned char  CRCText[];

Ich dachte wenn in C in der Klammer nichts steht dann ist die 
Stringlänge variabel? Geht leider nicht.

Wie kann ich machen dass ich jede Länge Text eingeben kann?


Grüsse

Maria

von Ulrich (Gast)


Lesenswert?

Du hast nicht nur einen Fehler gemacht ;-)

1. Buffer Overflow weil an jeden String wird eine \0 angehängt. also 
brauchst du für 8Zeichen 9Bytes!!!
2. Du willst bestimmt dass hier:
unsigned char  CRCText[] = {"CRC-Test"};
3. Man kann keinen kompletten string mit dem Zuweisungoperator >>=<< 
während des weiteren Programmablaufes zuweisen. Dazu benötigt man die 
Funktion: strcpy() oder strcat()

Mfg
Ulrich

von johnny.m (Gast)


Lesenswert?

> unsigned char  CRCText[8];
> CRCText = "CRC-Test";
Das ist aber schon nicht i.O.. "CRC-Test" hat nicht 8, sondern 9 
Zeichen. Spätestens, wenn hinter dem String etwas anderes gespeichert 
wird, geht Dir der Nullterminator flöten und eventuell zur Ausgabe 
benutzte Funktionen finden das String-Ende nicht!

Eine Deklaration eines Strings braucht immer entweder eine Anzahl der 
Feldelemente oder eine explizite Definition. Also
1
unsigned char string1[] = "CRC-Test";
funktioniert immer...

von johnny.m (Gast)


Lesenswert?

Huch, da war ich aber erheblich zu langsam... Kommt davon, wenn man beim 
Schreiben unterbrochen wird...

von Karl H. (kbuchegg)


Lesenswert?

> Ich dachte wenn in C in der Klammer nichts steht dann ist die
> Stringlänge variabel?

Und um das auch noch explizit anzusprechen.

1) In C gibt es eigentlich keinen eigenen Datentyp
   für "String"

2) Strings werden in character Arrays gespeichert

3) Es ist deine Aufgabe dafür zu sorgen, dass das
   Array gross genug ist. Dabei das abschliessende '\0'
   Zeichen nicht vergessen

4) Der Compiler hilft dir und befreit dich von ermüdender
   und fehleranfälliger Zeichenzählerei, indem er bei

   char Text[] = "Mein Text";

   die Zeichen selbst abzählt und das Array entsprechend gross
   macht, sodass der komplette Text, inklusive '\0' Zeichen
   da drin Platz hat.

5) Alles darüber Hinausgehende, ist das Bier des Programmierers.

von Rolf Magnus (Gast)


Lesenswert?

Jaja, die Geschichte der Arrays und Zeiger ist eine Geschichte voller 
Mißverständnisse.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Allerdings fragt man sich, warum das so ist - am Urtext von Kernighan & 
Ritchie kann es zumindest seit dessen zweiter Ausgabe nicht liegen, der 
beschreibt das eigentlich ganz anständig. Und die deutsche Übersetzung 
ist auch in Ordnung (ganz im Gegensatz zu der der ersten Ausgabe).

Vielleicht fangen zu viele Leute mit so merkwürdigen Programmiersprachen 
wie Basic, Pascal, Delphi, Java, C# etc. an ... die einem vor den harten 
Tatsachen des Lebens schützen wollen.

von johnny.m (Gast)


Lesenswert?

Wer liest schon ein echtes C-Buch? Dafür gibts doch Foren im Internet...

von Rahul, der Trollige (Gast)


Lesenswert?

>(ganz im Gegensatz zu der der ersten Ausgabe).
Ich finde die erste Ausgabe immer noch "besonders gut" (von einem 
Computer übersetzt) - das dürfte ein Klassiker werden.

von Gast (Gast)


Lesenswert?

>Aber warum kann ich einen String unbekannter Länge so nicht deklarieren?
>
>unsigned char  CRCText[];

Ich glaube so geht es:
unsigned char*  CRCText;
CRCText = "CRC-Test";

Die schon genannten Lösungen mit gleichzeitiger Deklaration und 
Zuweisung dürften aber effizienter sein.

Frag mich nicht, was genau der Unterschied zwischen char*  und char[] 
ist, hatte deine Probleme aber auch schon.


von Rahul, der Trollige (Gast)


Lesenswert?

>Ich glaube so geht es:


Sind wir hier in der Kirche?

>Frag mich nicht, was genau der Unterschied zwischen char*  und char[]
>ist, hatte deine Probleme aber auch schon.

Eigentlich sollte man dir dafür den K&R um die Ohren hauen.
char* ist ein Pointer auf ein Byte.
char[] veranlasst den Compiler dazu, ein entsprechend grosses Array 
(inkl. "\n") anzulegen.
Auf das Array wird durch einen Pointer zugegriffen.

von johnny.m (Gast)


Lesenswert?

> Sind wir hier in der Kirche?
Amen...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rahul, der Trollige wrote:

> Eigentlich sollte man dir dafür den K&R um die Ohren hauen.
> char* ist ein Pointer auf ein Byte.
> char[] veranlasst den Compiler dazu, ein entsprechend grosses Array
> (inkl. "\n") anzulegen.
> Auf das Array wird durch einen Pointer zugegriffen.

Wobei man der Gerechtigkeit halber sagen muss, dass die erste Form
natürlich ebenfalls ein Array anlegt, das hat nur keinen Namen, und
wenn man den Zeiger darauf ,,vergessen'' hat (weil man z. B. mit
Pointerarithmethik CRCText++ ausgeführt hat), gibt es niemanden
mehr, der den im Speicher vorhandenen Inhalt dieses Arrays noch
legal dereferenzieren kann.  Gewissermaßen ist
1
char *foo = "Text";

sowas wie
1
char invisible[] = "Text"; char *foo = invisible;

wobei der Namen invisible danach ,,vergessen'' wird.

von Karl H. (kbuchegg)


Lesenswert?

Wobei es noch einen Fehler gibt.

Eigentlich müsste es korrekterweise
1
const char* foo = "Text";

heissen.

Illegal wäre auch
1
  char* foo = "Text";
2
  foo[2] = 's';
weil foo ja auf ein String-Literal zeigt und das ist per Definition
konstant also nicht änderbar.

wohingegen
1
  char foo[] = "Text";
2
  foo[2] = 's';
absolut legales und gültiges C ist. foo ist ein Array und wird
beim Erzeugen mit den Charactern 'T', 'e', 'x', 't', '\0' gefüllt.
Und wie bei jedem anderen Array kann man natürlich den Arrayinhalt
ändern.

Aber Rahul hat schon recht. Wer Pointer empfiehlt
ohne selbst zu wissen was er tut, dem sollte ...
Hey das ist mein K&R, den nimmst du nicht!

von Rolf Magnus (Gast)


Lesenswert?

> Frag mich nicht, was genau der Unterschied zwischen char*  und char[]
> ist, hatte deine Probleme aber auch schon.

Die hat praktisch jeder Anfänger, weil Zeiger und Arrays in C ziemlich 
unintuitiv sind. Es gibt viele Feinheiten, und erst wenn man alle davon 
kennt, versteht man die ganze Sache. Schon die verwirrende 
kontextabhängige Verwendung von [] ist ohne vernünftige Anleitung ein 
Mysterium:
1
char c[] = "Hello, world\n"; // c ist ein Array aus char
2
char c[]; // geht nicht.
3
4
void func(char c[]); // c ist ein Zeiger auf char

Wer hier glaubt, das dritte c sei ein Array, wundert sich unter 
Umständen nachher, warum sizeof() Müll zurückzugeben scheint.
Viele Anfänger glauben sowieso, Arrays und Zeiger seien dasselbe, oder 
daß char* der String-Typ von C sei, und benutzen diese Sachen 
entsprechend (char* c = "The number is " + 5;). Das sind zumindest die 
von mir am häufigsten beobachteten Fehler von C-Einsteigern. Da die 
Annahmen aber falsch sind, kracht's irgendwann, und man hat keine 
Ahnung, warum.
Daher würde ich auf jeden Fall ein gutes C-Buch empfehlen. Ich hab's 
zwar auch ohne geschafft, aber das hat wesentlich länger gedauert, als 
nötig gewesen wäre.

von Maria (Gast)


Lesenswert?

Hallo

Vielen Danke mal für eure Hilfe.

Mit gewisser Kritik hier habe ich Mühle.
Denn jeder fängt mal an.


Irgendwie gibt es hier nur 2 Arten Menschen.
1. Die die C beherrschen
2. Die anderen die C überhaupt nicht beherrschen

Was dazwischen wird von gewissen Leute gar nicht akzepiert.


Ich lese im Moment ein C++ Buch. Leider ist es nicht immer einfach 
alles zu verstehen. Es ist vielfach recht schwierig den Befehl in C zu 
finden den man in Delphi oder so schon kennt.

Ich suche im Moment den Befehl der in Delphi "Copy"  heisst.
In "Pelles C" Hilfe habe ich noch nichts gefunden oder habe es 
übersehen.



Gruss
Maria

von Rolf Magnus (Gast)


Lesenswert?

Es gibt zwei Arten Menschen:

1. Die, die kein Delphi können
2. Die, die glauben, jeder könnte es

SCNR (bitte nicht so ernst nehmen)

Was macht "Copy" in Delphi denn?

von Karl H. (kbuchegg)


Lesenswert?

Wenn du C++ machst, solltest du das Gerödel mit den
char-Arrays zunächst mal zur Seite legen. In
C++ gibt es die std::string Klasse. Die funktioniert
so, wie man sich eine String-Klasse vorstellt. Damit
ist es schon wieder Kunst etwas falsch zu machen.

Erst später, mit etwas mehr Erfahrung, komm nochmal
auf C-Strings (aka character Arrays und was damit
zusammenhängt) zurück.

> Was dazwischen wird von gewissen Leute gar nicht akzepiert.
Oh doch, das wird es durchaus.

Nur: was nicht akzeptiert wird ist, wenn jemand
einen schlechten Rat gibt. Nicht deshalb weil er sich
vertan hat, sondern weil er (wie er selbst sagt)
keine Ahnung hat, was da eigentlich vor sich geht.

Das ist schliesslich ja auch in deinem Interesse,
dass dieses aufgeklärt wird.

Ausserdem: So schlimm ist das hier gar nicht. Schau
mal in internationale News-Groups (comp.lang.c++,
comp.lang.learn-c-c++). Da werden ab und zu Leute regelrecht
zerfleischt. Dagegen ist das hier harmlos.



von Karl H. (kbuchegg)


Lesenswert?

> In "Pelles C" Hilfe

Was denn nun?
C oder C++ ?
Das sind 2 verschiedene Paar Schuhe.

von Papst (Gast)


Lesenswert?

Ich finde die gegenseitige und oft auch "selbstverschriebene" 
Beweihräucherung immer wieder schön. Weiter so Leute!

von Maria (Gast)


Lesenswert?

Ich weiss dass C++ und C nicht genau das selbe ist.

Ich habe mir ein Buch für C++ für die PC Programmierung gekauft
Somit hoffe ich dass ich C für AVR und C++ für PC mit einer Klappe 
schlage.

Mir ist jetzt schon klar dass jetzt viele dageben protestieren bin aber 
der Meinung dass ich in so kurzer Zeit schon viel erreicht habe.
Im Moment habe ich keine Lust noch zusätzlich ein Buch nur für C zu 
kaufen da neben den Kosten auch der Zeitaufwand steigt.


"Copy" in Delphi kopiert einen Teil aus einem String heraus


Beispiel:

strT :String
strT := Copy ('ABCDEF12345',3,4);
strT = 'CDEF';

von Gast (Gast)


Lesenswert?

>>Frag mich nicht, was genau der Unterschied zwischen char*  und char[]
>>ist, hatte deine Probleme aber auch schon.
>
>Eigentlich sollte man dir dafür den K&R um die Ohren hauen.

Das gute Ding!

>char* ist ein Pointer auf ein Byte.
>char[] veranlasst den Compiler dazu, ein entsprechend grosses Array
>(inkl. "\n") anzulegen.
>Auf das Array wird durch einen Pointer zugegriffen.

ebend: durch einen char*

Ich glaube immer noch, dass mein Vorschlag funktioniert.
Ciao, muss in die Messe

von Rolf Magnus (Gast)


Lesenswert?

In C etwa so:
1
char str[5];
2
strncpy(str, "ABCDEF12345"+2, 4)
3
str[4] = '\0';

In C++:
1
std::string str;
2
str = std::string("ABCDEF12345").substr(2, 4);

  

von Gast (Gast)


Lesenswert?

>Irgendwie gibt es hier nur 2 Arten Menschen.
>1. Die die C beherrschen
>2. Die anderen die C überhaupt nicht beherrschen
>
>Was dazwischen wird von gewissen Leute gar nicht akzepiert.

Es gibt noch die, die C überhaupt nicht beherrschen, die aber meinen, 
dass sie zu 1. gehören und noch deshalb nur ihre eigene flasche Meinung 
akzeptieren:

>Eigentlich müsste es korrekterweise
>
>const char* foo = "Text";

Wozu sollte das const nötig sein? Sicherlich ist es in den meisten 
Fällen sinnvoll, aber uneigentlich ist "char* foo = "Text";" genauso 
korrekt. Glaube ich.

von Maria (Gast)


Lesenswert?

Danke Magnus ich werde es ausprobieren.

von Marion (Gast)


Lesenswert?

In diesem Zusammenhang habe ich auch eine Frage an die Experten: ich 
brauche häufig Aufrufe wie

char s[10];
int x;
sprintf(s,"%10d",x); oder
sprintf(s,"x=%s",s2);

Wie kann ich hier Speicherfehler ausschließen? Zumindest beim ersten 
(Format %10d") kann man nicht sichergehen, dass tatsächlich nur 9 
Ziffern geschrieben werden, da ints in Zukunft beliebig groß werden 
könnten.
Beim zweiten (Format "x=%s", s2 ist ein zweiter char* auf eine 
Zeichenkette unbekannter Länge) kann ich gar keine Länge vorschreiben. 
Sicher, ich könnte das durch zwei strncpy's lösen, was aber deutlich 
umständlicher wird.

Gibt es sowas wie sNprintf, also eine sprintf-Funktion mit Angabe der 
maximalen Zeichenzahl?

Was macht man sonst? Vor jedem sprintf mit zig Abfragen checken, dass 
z.B. bei einem Format "%10d" die int-Variable nicht mehr als 10 Stellen 
hat? Oder einfach 10x mehr Speicher reservieren als für heutige ints 
nötig, und hoffen, dass das Programm nicht mehr eingesetzt wird, wenn 
die Genauigkeit von ints zu gross geworden ist?

Marion

von Chris (Gast)


Lesenswert?

>>Eigentlich müsste es korrekterweise
>>
>>const char* foo = "Text";

> Wozu sollte das const nötig sein? Sicherlich ist es in den meisten
> Fällen sinnvoll, aber uneigentlich ist "char* foo = "Text";" genauso
> korrekt. Glaube ich.

In C++ ist 'char* foo = "Text";' definitiv nicht korrekt, weil 
String-Literale nicht verändert werden dürfen. Es ist allerdings aus 
Kompatibilitätsgründen möglich diese Zeile zu schreiben, allerdings darf 
man das String-Literal "Text" eben niemals verändern, auch wenn foo auf 
nicht-konstante Zeichen zeigt.

Will man den String verändern ist in C++ nur ein Array korrekt:
char foo[] = "Text";


In C könnte allerdings auch die Zeiger-Variante korrekt sein. Das hängt 
davon ab, was der Standard dazu sagt (den ich leider nicht habe).

von Karl H. (kbuchegg)


Lesenswert?

> Das hängt davon ab, was der Standard dazu sagt (den ich leider
> nicht habe).

Seit der Einführung von const ist es eigentlich auch dort nicht
mehr korrekt. Aus den gleichen Gründen wie in C++.
Und ebenfalls aus den gleichen Gründen wie in C++ wird
das trotzdem akzeptiert: Rückwärtskompatibilität
zu bestehendem Code.

>>Eigentlich müsste es korrekterweise
>>
>>const char* foo = "Text";
> Wozu sollte das const nötig sein?

Weil der Zeiger auf ein String-Literal zeigt, dass per
Definition konstant ist.

Du darfst es nicht verändern.

Machst su

  char* foo = "Text;
  foo[2] = 's';

hast du einen Fehler begangen, vor dem dich der Compiler nicht
bewahren kann.

Machst du

  const* foo = "Text";
  foo[2] = 's';

dann klopft dir der Compiler auf die Finger.

Das
  char* foo = "Text";
überhaupt akzeptiert wird, hat den Grund, dass extra für
diesen Fall in den Standard eine Ausnahme eingebaut wurde.
Ansonsten hätte man praktisch jedes C-Programm auf dieser
Erde korrigieren müssen und diesen Aufwand wollte man den
Programmierern nicht zumuten.

'Moralisch' ist
  char* foo = "Text";
nicht korrekt. Durch die spezielle Ausnahmeregelung (die
völlig gegen die sonstige const-Regelung läuft) wird aber
dieser eine spezielle Fall der char Pointer zugelassen,
auch wenn er eigentlich falsch ist.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Maria wrote:

> Ich weiss dass C++ und C nicht genau das selbe ist.

Nein: es sind zwei sehr verschiedene Dinge, die zufällig einen
ähnlichen Namen haben und sich manche Sachen in der Syntax teilen.

Du musst dich aber schon entscheiden, ob du lieber erstmal C oder
lieber erstmal C++ lernen willst.  Es ist völlig richtig, dass sich
beides auf einem Universalrechner besser lernen lässt als auf einem
Controller mit seinen eher beschränkten Ressourcen und schlechteren
Debugmöglichkeiten.

C++ auf Controllern kann man auch machen, allerdings sollte man dann
bereits mit den Feinheiten der Sprache vertraut sein und ungefähr
wissen, welche Sprachkonstrukte sich größenordnungsmäßig in welchem
Code niederschlagen, ansonsten kann man hinsichtlich des
Ressourcenverbrauchs schnell sein blaues Wunder erleben.

von Karl H. (kbuchegg)


Lesenswert?

> Gibt es sowas wie sNprintf, also eine sprintf-Funktion mit
> Angabe der maximalen Zeichenzahl?

Ja gibt es.


von Rolf Magnus (Gast)


Lesenswert?

> In C++ ist 'char* foo = "Text";' definitiv nicht korrekt, weil
> String-Literale nicht verändert werden dürfen.

Es ist durchaus korrekt.

> Es ist allerdings aus Kompatibilitätsgründen möglich diese Zeile zu
> schreiben, allerdings darf man das String-Literal "Text" eben niemals
> verändern, auch wenn foo auf nicht-konstante Zeichen zeigt.

Genau. Das macht das obige aber nicht zu inkorrektem, sondern nur zu 
unsauberem Code.

> In C könnte allerdings auch die Zeiger-Variante korrekt sein.

Stringliterale dürfen da genausowenig verändert werden, wie in C++.

von Rahul, der Trollige (Gast)


Lesenswert?

[OT]
>Maria
>Marion

Wieso wollen die "Weiber" eigentlich immer Sachen machen, die "Männern" 
Spaß machen? Können die nicht lieber Kochen lernen? Und Kinder kriegen?
[/OT]

von Marion (Gast)


Lesenswert?

>> Gibt es sowas wie sNprintf, also eine sprintf-Funktion mit
>> Angabe der maximalen Zeichenzahl?
>
>Ja gibt es.

Jetzt wo du es sagst...
Hätte einfach nach meinem Verdacht googeln müssen, wäre schneller 
gegangen, als meine Frage hier zu stellen.

von Marion (Gast)


Lesenswert?

>Können die nicht lieber Kochen lernen? Und Kinder kriegen?

Können wir beides schon

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.