Funktion um zwei Strings zu addieren



  • Weil ich nicht weiß, wie man in C mit Zeichenketten umgeht, wollte ich zur Übung eine Funktion schreiben, die zwei zeichenketten aneinanderhäängt:

    int addstr(char str1[], char str2[], char buffer[])
    {
      // hier solll jetzt Zeichenkette str1 mit str2 verbunden werden
      // und das Ergebni soll in buffer abgelegt werden. Rückgabewert der Funktion,
      // wäre die Gesamtlänge der resultrierenden Zeichenfolge
    }
    

    Allerdings hab eich schon beim Übergeben Probleme:

    int addstr(char str1[], char str2[], char buffer[])
    {
    	MessageBox(0, (LPCWSTR)str1, L"Test", 0);
    
    	return strlen(buffer);
    }
    

    In der MessageBox stehen nur Kästchen.

    Ich benutze das VC2005 und es sollen keine WideStrings, also kein Unicode, sein.



  • Luckie schrieb:

    In der MessageBox stehen nur Kästchen.

    ... weil du versuchst ein char* als wide chars auszugeben.
    also verwende 'wchar_t*' statt 'char*' und zum aneinanderhängen z.b. 'wcscat'.

    ach so: wenn es keine wide chars sein sollen dann nimm 'strcat' zum zusammenkleben und 'MessageBoxA' statt 'MessageBox' zum ausgeben.



  • Danke schon mal für die Antwort. Ich habe es jetztz erstmal so:

    extern "C" EXPORT int addstr(char *str1, char *str2, char *buffer)
    {
    	MessageBoxA(0, str1, "Test", 0);
    
    	return strlen(str1);
    }
    

    Leider bekomme ich so immer eine Zugriffsverletzung beim Aufruf der Funktion. Ich sollte eventuell dazu sagen, dass sie in einer DLL liegt, aber das sollte erstmal keine Rolle spielen.



  • die msgbox sieht eigentlich ok aus, muss irgendwie am aufruf liegen.

    btw: aber lass dich mal besser nach 'winapi' verschieben....



  • Also entschuldige, aber

    Luckie schrieb:

    Weil ich nicht weiß, wie man in C mit Zeichenketten umgeht

    in Verbindung mit

    Luckie schrieb:

    Ich sollte eventuell dazu sagen, dass sie in einer DLL liegt, aber das sollte erstmal keine Rolle spielen.

    hört sich böse an 😉

    Greetz, Swordfish



  • Die MessageBox war ja ursprünglich nur zur Kontrolle drinne. Um die geht es mir ja eigentlich gar nicht. Ich will eiegntlichn ur eine Funktion, die mir zwei Zweichenketten aneinanderhängt und das Ergebnis in den Parameter Buffer schreibt.

    Das mit der MessageBox hat sich erledigt, ich hatte vergessen in Delophi die Aufrufkonvention anzugeben. Jetzt sieht es so aus:

    extern "C" EXPORT int addstr(char *str1, char *str2, char *buffer)
    {	
        strcat(str1, str2);
        strcpy(buffer, str1);
        return strlen(buffer);
    }
    

    Jetzt bekomme ich aber wieder eine AccessViolation in der DLL. Mein korrespondierender Delphi Code sieht so aus:

    type
      TAdd = function(a, b: Integer): Integer; stdcall;
      TAddStr = function(str1, str2: PChar; var Buffer: PChar): Integer; stdcall;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      hLib: THandle;
      s: String;
      Add: TAdd;
      AddStr: TAddStr;
      res: Integer;
      str1, str2: String;
      Buffer: PChar;
    begin
      s := IncludeTrailingBackSlash(ExtractFilePath(ParamStr(0)))+ 'FirstDLL.dll';
      hLib := LoadLibrary(PChar(s));
      if hLib <> 0 then
      begin
        @Add := GetProcAddress(hLib, 'add');
        if Assigned(Add) then
        begin
           res := Add(40, 2);
           ShowMessage(IntToStr(res));
        end
        else
          ShowMessage(SysErrorMessage(GetLastError));
    
        @AddStr := GetProcAddress(hLib, 'addstr');
        if Assigned(AddStr) then
        begin
          str1 := 'Hello ';
          str2 := 'World';
          GetMem(Buffer, length(str1) + length(str2));
          try
            res := AddStr(PChar(str1), PChar(str2), Buffer);
            ShowMessage(string(Buffer));
          finally
            FreeMem(Buffer);
          end;
        end
        else
          ShowMessage(SysErrorMessage(GetLastError));
        FreeLibrary(hLib);
      end
      else
        ShowMessage(SysErrorMessage(GetLastError));
    end;
    


  • Luckie schrieb:

    extern "C" EXPORT int addstr(char *str1, char *str2, char *buffer)
    {	
        strcat(str1, str2);
        strcpy(buffer, str1);
        return strlen(buffer);
    }
    

    Jetzt bekomme ich aber wieder eine AccessViolation in der DLL.

    da ist wohl ein speicherbereich zu klein.
    mach besser sowas:

    int addstr (char *str1, char *str2, char *buffer)
    {	
        return sprintf (buffer, "%s%s", str1, str2);
    }
    

    btw: wieso ärgerste dich mit c rum wenn du delphi hast 😉



  • Hier http://www.delphipraxis.net/post595290.html#595290 ist die Lösung.

    Gute Frage. Cheffe will die DLL unbedingt in C haben (und mit GCC und Ecliipse, aber da sist eine andere Geschichte). Und da übe ich schon mal etwas und gucke mir das an. Da ich in Delphi aber etzwas fitter bin, habe ich die Testanwendung eben in Delphi schnell geschrieben.



  • Luckie schrieb:

    Hier http://www.delphipraxis.net/post595290.html#595290 ist die Lösung.

    jo, ist das selbe nur dass du's mit 3 funktionsaufrufen machst 😉



  • Jupp. Aber es ging mir nur ums Prinzip. 😉



  • Luckie schrieb:

    extern "C" EXPORT int addstr(char *str1, char *str2, char *buffer)
    {	
        strcat(str1, str2);
        strcpy(buffer, str1);
        return strlen(buffer);
    }
    

    Jetzt bekomme ich aber wieder eine AccessViolation in der DLL.

    Na bravo! Das ist mal wieder eins der typischen Beispiele dafür,
    was passieren kann, wenn man unsauber programmiert.

    Ich gehe mal davon aus, daß die übergebenen Strings nicht
    verändert werden sollen; genau das macht dieser Code aber!

    Er versucht str2 an den bestehenden str1 anzuhängen und danach
    den jetzt veränderten str1 zu kopieren. 😮

    Bei sauberer Nutzung des Modifiers const wär' das nicht passiert:

    extern "C" EXPORT int addstr(const char *str1, const char *str2, char *buffer)
    {	
        strcat(str1, str2);
        strcpy(buffer, str1);
        return strlen(buffer);
    }
    

    Da hätte nämlich der Compiler bereits losgemeckert! 🕶



  • Wärest du meinem Link gefolgt, dann hättest du gesehen, dass ich es mittlerweile geändert habe und es jetzt läuft.



  • Luckie schrieb:

    Wärest du meinem Link gefolgt, dann hättest du gesehen, dass ich es mittlerweile geändert habe und es jetzt läuft.

    Eben nicht!

    Ein Aufruf von z.B. addstr("Hello ", "world!", buffer);
    dürfte bei deiner Signatur nicht möglich!

    Und gerade als als Moderator eines Programmierforums solltest du
    doch mit gutem Beispiel vorangehen.



  • Und warum sollte das nicht möglich sein? Und was hat meine Funktion als Moderator damit zu tun?



  • hi luckie. javaner ist nun mal *javaner*, kennt "const correctness" von c++ und denkt, c haette das auch. hats aber nicht.
    konkret denkt er, dass der compiler fehler spuckt, wenn eine funktion(const char*) mit einem einfachen char* aufgerufen wird (oder umgedreht). das gibt bei gcc gerade mal ne warnung, *wenn* man masochistische flags verlangt.

    nichtsdestotrotz verlangt C eine definitiv andere denkweise als delphi, insbesondere bei der stringbehandlung. ich moechte behaupten, beide welten zu kennen (ja, AnsiString ist ein record, welches einen fucked string enthaelt) und kann dir zumindest das verraten.



  • c.rackwitz schrieb:

    hi luckie. javaner ist nun mal *javaner*, kennt "const correctness" von c++ und denkt, c haette das auch. hats aber nicht.
    konkret denkt er, dass der compiler fehler spuckt, wenn eine funktion(const char*) mit einem einfachen char* aufgerufen wird (oder umgedreht).

    ... das wäre aber auch legales C++ ... wenn du auf 'char *p = "foobar";' anspielst.

    Da"duck&cover"niel



  • c.rackwitz schrieb:

    nichtsdestotrotz verlangt C eine definitiv andere denkweise als delphi, insbesondere bei der stringbehandlung.

    Und genau damit versuche ich mich gerade vertraut zu machen, weil ich das bei einem kommenden Projekt brauchen werden.



  • c strings sind nur eine null-terminierte kette von bytes im speicher

    man kommt nur mittels zeiger aufs erste zeichen an sie ran

    die laenge ist nicht teil des strings, sie muss ermittelt werden (durchscannen nach nullzeichen)

    stringoperationen wie z.b. strcat sind wahnsinn: laufzeit O(n+m) fuer strcat, weil beide strings ganz gelesen werden muessen
    eine kette von strcat()s sollte/muss handoptimiert werden (einen zielpointer mitschleppen, um das durchscannen zu reduzieren), sonst hast du einen shlemiel: http://www.joelonsoftware.com/articles/fog0000000319.html

    es gibt stringliterale (literal eben, der kram zwischen den quotes) und die sind read-only. schreibversuch in ein literal resultiert demnach in einer zugriffsverletzung.

    arrays kann man mit literalen initialisieren. dann kannst du ins array schreiben, aber das literal hat damit seine schuldigkeit getan.

    ein array char foo[1000] = "hallo welt": ist 1000 bytes lang und die ersten so und so viel bytes enthalten die offensichtlichen zeichen, gefolgt von einem nullbyte (welches am ende von literalen uebrigens nichts zu suchen hat, wie manche es gerne machen). die laenge des *strings* ist vom nullbyte abhaengig. wenn du uber die arraygrenzen schreibst (was in c nicht mal bewarnt werden kann), hast du einen stack buffer overflow.

    bei der uebergabe von arrays an eine funktion wird nur ein pointer uebergeben (ne zahl eben). in der funktion kannst du das richtige machen und den parameter als pointer ansehen, oder du kannst so tun als ob der parameter ein array waere und in der funktionsdefinition fuer diesen parameter dimensionen angeben:

    void foo(char *str) {}
    void bar(char str[100]) {} // keiner garantiert, dass die funktion auch echt einen char[100] kriegt, aber wir tun mal so...
    

    sizeof funktioniert so: sizeof(char[]) == laenge in bytes des verfuegbaren speichers; sizeof(char*) == wortgroesse in bytes. sizeof() ist also nutzlos, um die laenge eines strings zu bestimmen.



  • Die Tatsache, dass unter C Zeichenketten nur nullterminierende zeichen-arrays sind, war mir schon bekannt. 😉

    Und den Artikel von Joel kenne ich auch. Er schreibt sehr gut, wenn auch manchmal etwas langatmig.



  • @Luckie

    Ich muß mich für meine gestrige Behauptung
    entschuldigen; du hattest doch Recht! 🙄

    Die Compiler mit denen ich zuvor zu tun hatte (Solaris, Atari)
    verlangten nach Einführung des const-Modifiers die
    const-correctness.

    Dies war auch der Grund dafür,
    daß wir bei Zusammenarbeit mit Siemens-Teams zu Anfang
    immer Schwierigkeiten hatten. Diese lieferten uns C++-Header-Dateien
    in denen (wegen Faulheit der Siemens-Programmierer) viele
    Zeiger-Parameter nicht als const deklariert wurden, wobei
    wir diese Funktionen mit const-Parametern aufrufen wollten.

    Das es heute auf einmal anders ist, ist mir entgangen

    http://www.c-plusplus.net/forum/viewtopic-var-t-is-156434.html

    Weiß jemand einen Link auf die heute gültigen Sprachspezifikationen?


Anmelden zum Antworten