Mark: C struct array kopieren

Hallo,

ich habe in C ein kleine Problem. Codeauszug:

struct eintrag  
{  
	char name[40];  
	char vorname[20];  
	char nummer[20];  
};  
struct eintrag telefonliste[20];

Annahme: Telefonliste ist komplett gefüllt.

Jetzt kommt eine Schleife, die ab eine bestimmten Wert (d) immer den Wert des nächst höheren Datensatzes in den geraden aktuellen schreiben soll. Also werden alle Werte höher als d um ein nach unten verschoben.

for(int j=d-1; j<i; j++)  
{  
telefonliste[j].name=telefonliste[j+1].name;  
telefonliste[j].vorname=telefonliste[j+1].vorname;  
telefonliste[j].nummer=telefonliste[j+1].nummer;  
}

Leider gibt mir der Compiler einen Fehler ('=': Linker Operand muss ein L-Wert sein). Was könnte Abhilfe schaffen, ohne dass ich noch for-Schleifen schreiben muss, die Zeichen für Zeichen kopieren, bis das Ende des jeweiligen Arrays (name, vorname, nummer) errreicht ist?

  1. Hallo Mark,

    struct eintrag

    {
    char name[40];
    char vorname[20];
    char nummer[20];
    };

      
    warum markierst du einen C-Codeauszug hier im Posting als "PHP" anstatt als C? ;-)  
      
    
    > ~~~c
    
    for(int j=d-1; j<i; j++)  
    
    > {  
    > telefonliste[j].name=telefonliste[j+1].name;  
    > telefonliste[j].vorname=telefonliste[j+1].vorname;  
    > telefonliste[j].nummer=telefonliste[j+1].nummer;  
    > }
    
    

    Das geht so natürlich nicht, denn <eintrag>.name ist ja kein Basisdatentyp, sondern ein Array.

    Leider gibt mir der Compiler einen Fehler ('=': Linker Operand muss ein L-Wert sein).

    Ja. Mit L-Wert oder LValue meinen die Compiler einen Ausdruck, dem man einen Wert zuweisen kann. Es muss deshalb ein Ausdruck sein, der zum einen auf eine Speicheradresse verweist, zum anderen eine Information über den Datentyp enthält. Ein void* verweist beispielsweise eindeutig auf eine Speicheradresse, hat jedoch keine Typinformation und ist somit kein LValue.

    In deinem Fall ist ein char[] zwar technisch gesehen ein LValue, aber in C kann man nur Basistypen direkt zuweisen. Um ein ganzes Array zu kopieren, muss man jedes Element (in deinem Fall: jedes Zeichen) einzeln anfassen.

    Zum Glück gibt es aber fertige Funktionen dafür. Die Funktion memcpy() und ihre Derivate könnten dich interessieren; wahrscheinlich sogar noch eher strcpy() und seine Verwandten, vorzugsweise strncpy(). Mit memcpy() könntest du allerdings auch die gesamte Struktur auf einmal kopieren.

    So long,
     Martin

    --
    Wer im Glashaus sitzt, sollte Spaß am Fensterputzen haben.
    1. warum markierst du einen C-Codeauszug hier im Posting als "PHP" anstatt als C? ;-)

      oh, wusste nicht, dass es auch eine C-Markierung gibt. Habe es jetzt aber gefunden ;-). Werde ich beim nächsten mal auf jeden Fall verwenden.

      Zum Glück gibt es aber fertige Funktionen dafür. Die Funktion memcpy() und ihre Derivate könnten dich interessieren; wahrscheinlich sogar noch eher strcpy() und seine Verwandten, vorzugsweise strncpy(). Mit memcpy() könntest du allerdings auch die gesamte Struktur auf einmal kopieren.

      Vielen Dank. Ich werde mich damit beschäftigen.

    2. Hallo,

      was ich noch vergessen hatte zu schreiben, ich habe auch schon folgendes probiert:

      for(int j=d-1; j<i; j++)  
      {  
      *telefonliste[j].name=*telefonliste[j+1].name;  
      *telefonliste[j].vorname=*telefonliste[j+1].vorname;  
      *telefonliste[j].nummer=*telefonliste[j+1].nummer;  
      }
      

      Hier kopiere ich ja die Adressen, warum geht das nicht? Da müsste ich wenigstens nicht die kompletten Daten kopieren.

      Gruß

      Mark

      1. Hi,

        was ich noch vergessen hatte zu schreiben, ich habe auch schon folgendes probiert:
        [...]
        *telefonliste[j].name=*telefonliste[j+1].name;

        das ist syntaktisch in Ordnung - aber nicht das, was du willst. Damit kopierst du von jedem String nur das erste Zeichen. Diese Anweisung ist vollkommen äquivalent zu

        telefonliste[j].name[0]=telefonliste[j+1].name[0];

        Ein '*' vor einem Ausdruck ist der sogenannte Dereferenzierungs-Operator[1]. Es bedeutet: Interpretiere den Ausdruck nach dem '*' als Zeiger und nimm das Element, auf das er verweist. Hier ist telefonliste[x].name wieder vom Typ char[]. Ein Array eines Typs ist aber in C-Ausdrücken äquivalent zu einem Zeiger auf diesen Typ, ein char[] ist also gleichbedeutend mit einem char*. Deswegen ergibt der Ausdruck *telefonliste[x].name nur ein einzelnes Zeichen.

        Ciao,
         Martin

        [1] Wow, wirklich ein toller Ausdruck!

        --
        Zwei Politiker auf dem Weg zum Sitzungssaal: "Was sagten Sie in ihrer Rede neulich noch zur Rentenreform?" - "Nichts." - "Ja, schon klar. Aber wie haben Sie es formuliert?"
        1. Vielen Dank, habe ich geschnackelt ;-)

      2. Hier kopiere ich ja die Adressen, warum geht das nicht? Da müsste ich wenigstens nicht die kompletten Daten kopieren.

        Hi Mark,

        in diesem Ansatz hast Du auch einen grundsätzlichen Denkfehler. Es besteht ein Unterschied zwischen Zeigern, die auf einen fest allokierten Speicherbereich zeigen und Zeigern, die (quasi) frei beweglich sind. Mit der Deklaration eines Arrays aus Strukturelementen allokierst Du einen Buffer, der an einer bestimmten Stelle im Speicher liegt. Über die Indizes Deines Arrays und die Sturkturelemente kannst Du auf ganz bestimmte Stellen in diesem Buffer zugreifen.

        Da in C jedes Array durch einen Zeiger auf sein erstes Element gekennzeichnet ist, kannst Du theoretisch so einen Zeiger auch verschieben (der C-Compiler erlaubt eine Menge, was nicht sinnvoll ist...), aber Du solltest es tunlichst vermeiden, denn das widerpricht dem Sinn und und Zweck dieses Zeigers. Einer der frei beweglich sein soll, sollte auch so deklariert sein, also nur als Zeiger, ohne Datenbereich "dahinter".

        Prinzipiell ist natürlich eine Lösung nach Deiner Idee möglich, bei der lediglich die Adressen der Strings kopiert werden. Dann brauchst Du aber eine Struktur, die schon durch die Deklaration lediglich Zeiger enthält - und den Buffer mit den ganzen Daten (oder einzelne, kleinere Buffer) musst Du Dir zusätzlich anders erzeugen. In der Tat wird man in einem Buffer meist nicht die Daten hin und her kopieren, sondern den Zugriff auf die Elemente anders organisieren. Die Frage ist halt, wie bei der tatsächlichen Anwendung am sinnvollsten (und auch am verständlichsten) erscheint.

        Grüsse
        Stefanie