Warum funktioniert 1 String unbekannter Länge so nicht?

Gast #503848
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
Gast #503873
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
Gast #503875
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...
#503950
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.
Persönliche Seite #503994
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.
Gast #504071
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.

Gast #504090
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.
Moderator Persönliche Seite #504118
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.
#504168
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!
Gast #504169
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.
Gast #504222
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
#504229
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.


Gast #504241
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';
Gast #504276
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
Gast #504283
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.
Gast #504305
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
Gast #504350
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).
#504375
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.
Moderator Persönliche Seite #504432
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.
Gast #504555
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++.
Gast #504768
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren