Format-Probleme mit übergabe eines Strings an eine Funktion. (Auch Heap-Block Problem)
-
Hm. Da sind zwar viele archaische C-Elemente drin, aber der COM-Teil ist C++. Ins C-Forum gehört das so eigentlich nicht.
Wie dem auch sei, das Problem ist stumpf, dass du die Dokumentation zu ISpVoice::Speak nicht oder nicht richtig gelesen hast. Der erste Parameter ist der Satz, der gesprochen werden soll bzw. ein Dateiname als LPCWSTR - d.h. wchar_t const * - da wirst du mit char[100] nicht weit kommen. Der zweite Parameter, in den du den char[100] zu stopfen versuchst, nimmt Flags als DWORD entgegen; was der String da soll, ist mir schleierhaft.
Jedenfalls hat das Ding stumpf keine eingebaute Formatierungsfunktionalität. Du wirst dir den LPCWSTR vorher zusammenbauen müssen.
-
Hi,
deshalb, weil es eben eigentlich ein C++ Programm ist, hatte ich das Thema auch dort hinein geschrieben. Aber egal. "Gelernt" habe ich C. Eigentlich auch nur sehr wenig.
Ich habe lange gesucht gestern und nichts gefunden wie ich einen String im LPCWSTR-Format übergebe oder richtig deklariere. Manches war C++ und deshalb habe ich das nicht verstanden.
Wenn ich versuche den char-String in LPCWSTR zu casten kommt ein fehler, das er das nicht kann. Das habe ich auch schon mit wchar_t versucht und gleich alles in wchar_t zu machen geht auch nicht.Ist es denn überhaupt die richtige Stelle wo ich versuchen die Variabel "x" einzufügen? Wenn ich das in irgendeinen DWORD stopfe, wo kommt es dann wirklich rein? Ich dachte das wäre so wie mit printf ...
Aus dem Link werde ich nicht schlau. Nur das pcws LPCWSTR haben will, aber ob das nun der Satz wird, der gesprochen wird, keine Ahnung.
Ich wusste auch garnicht das es dazu eine Dokumentation gibt. ^^ Ich dachte richtige Programmierer verstehen das einfach so oder gucken sich die Funktion in der Header-Datei an und fertig.Bitte bedenkt das ich noch sehr wenig Erfahrung habe und mit C++ keine.
MfG
-
Ok..
nach weiterem stundenlangen suchen und probieren, funktioniert nun folgendes:
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <sapi.h> int ausgabe(const char ansistr[80]) { int i=0; int len = MultiByteToWideChar(CP_ACP, 0, ansistr, -1, NULL, 0); LPWSTR unicodestr = (LPWSTR)malloc(len); // free() nicht vergessen!?? MultiByteToWideChar(CP_ACP, 0, ansistr, -1, unicodestr, len); ISpVoice * pVoice = NULL; if (FAILED(::CoInitialize(NULL))) return FALSE; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); if( SUCCEEDED( hr ) ) { hr = pVoice->Speak(unicodestr, 0, NULL); pVoice->Release(); pVoice = NULL; } //free(unicodestr); //Verursacht Heap-Block fehler. ::CoUninitialize(); return TRUE; } int main() { int ende=0; while(ende!=1) { if(_kbhit())//Taste gedrückt? { char ch=_getch(); if(ch=='\0')ch=_getch();//Sondertasten werden als 0;xx eingelesen switch(ch) { case 107: printf("Taste K gedrueckt.\n"); ausgabe("Taste K gedrueckt."); break; case 109: printf("Taste M gedrueckt.\n"); ausgabe("Taste M gedrueckt."); break; case 27: ende=1; break; } } } system("PAUSE"); }
Allerdings sollte ich doch den Speicher freigeben, der durch "malloc(len)" zugewiesen wurde, oder nicht? Ich weiß nicht was für Auswirkungen das haben kann, wenn man das nicht macht. Später wird das Programm Wochenlang laufen und ständig werden Strings an die "ausgabe"-Funktion übergeben.
Wenn ich versuche den Speicher mit free() freizugeben, bekomme ich "Heap Block"-Fehler.
Ich muss das doch so eingeben, oder: "free(unicodestr);"?Per Google habe ich dazu nichts richtiges gefunden. Schließlich verursacht nur der "free()"-Befehl diesen Fehler.
Danke schonmal.
MfG
-
Was soll das denn bedeuten?
LPWSTR unicodestr = (LPWSTR)malloc(len); // free() nicht vergessen!??
Ist das ein Zeiger?
Mit C++ hat ich bisher noch nichts zu tun, aber ein Zeiger sollte es doch sein.
Dann klappt es auch mit dem free(). Der braucht ja den Zeiger auf den Speicherbereich.
Wenn du nicht freest und das Programm länger laufen sollte, dann wirst du mit der Zeit Speicherprobleme bekommen, sofern stetig Speicher akquiriert wird.
Edit: Bei dynamischer Speicherverwaltung solltest du immer aufpassen, Fehler können sich da meist erst etliche Zeilen später bemerkbar machen.
Folgendes gilt nicht immer:
'\0' bzw. 0 dient als Stringterminierung
NULL dient als Arrayterminierung(z.B. bei den exec Funktionen die Parameter als Array empfangen, bei argc hingegen nicht)
-
DaRe schrieb:
Was soll das denn bedeuten?
LPWSTR unicodestr = (LPWSTR)malloc(len); // free() nicht vergessen!??
Ist das ein Zeiger?
Mit C++ hat ich bisher noch nichts zu tun, aber ein Zeiger sollte es doch sein.
Dann klappt es auch mit dem free(). Der braucht ja den Zeiger auf den Speicherbereich.
Ich habe keine Ahnung was du meinst ...
Kannst du das bitte etwas einfacher formulieren??Auf jeden Fall gibt es ein HeapBlock-Problem wenn ich "free(unicodestr)" wieder einfüge, also die // entferne.
EDIT: Ok ok ... warum müsst ihr immer so komisch Antworten? Sagt doch einfach: "Die free-Funktion braucht einen Zeiger der auf den Speicher zeigt, der vorher zugewiesen wurde. Ein Zieger wird mit '*ptr', in dem Fall hier '*unicodestr', angegeben. Du hast also das Sternchen vergessen. Desweiteren muss die ganz Zeile eigentlich so aussehen: void free(void *unicodestr);"
Sowas hilft viel besser ^^. So musste ich erst suchen was denn überhaupt ein Zeiger ist und noch ein Paar Meldungen in Visual c++ interpretieren (wegen den void), damit das überhaupt funzt.
Aber danke dir das du mich auf die Lösung gebracht hast.MFG
-
Na siehst du mal, die eigene aufgewendete Arbeit bleibt auch länger im Kopf, als wenn ich es dir 100 pro vorbete Edit: Aso, in C++ heißt das ja glaube schon Referenz *hehe*
Das ist dir aufgefallen?:
LPWSTR unicodestr = (LPWSTR)malloc(len);unicodestr ist ja mittlerweile schon ein Pointer.
Da du in C++ arbeitest, soll man ja dann auch malloc casten, aber nicht mehr auf (LPWSTR), sondern auf (LPWSTR
-
Der code ist nicht von mir sondern irgendwo kopiert. Das hatte jemand jemandem geschrieben der das gleich Problem hatte wie ich. Und den Code habe ich auch nicht vollständig verstanden.
Was meinst du mit: "Das ist dir aufgefallen?" ???
Und wie caste ich malloc auf (LPWSTR *)? Kannst du mir wenigstens das Schreiben? Ich habe gerade andere Probleme nach denen ich suche. Mein Programm funktioniert nämlich ohne Probleme wenn ich es in der IDE ausführe, aber nicht mehr wenn ich die EXE im Explorer ausführe. Statisch gelinkt ist eingestellt.
Beim Zweiten Ausführen von "ausgabe" stürzt die Anwendung ab. Aber eben nur wenn ich die kopilierte Anwenundg im Explorer doppelklicke. Und dafür suche ich jetzt gerade schon nach Lösungen.MfG
-
Ich bin mir nicht sicher, ob du das mit dem malloc genauso umgesetzt hast.
malloc liefert dir einen Zeiger auf einen Speicherbereich zurück, den man dann auf einen Zeiger castet und in einem entsprechenden Zeiger speichert.
LPWSTR *unicodestr = (LPWSTR *)malloc(len);
-
Ich habe malloc überhaupt nich umgesetzt. Das waren andere. Ich habe nur kopiert. Allerdings scheint es ja zu funktionieren. Das Free geht ja jetzt auch. Also warum soll ich noch was ändern?
Wenn ich einen Stern vor unicodestr setze muss ich das überall tun, da sich damit der Name der Varible verändert. Dann gibt es allerdings Speicher-zugriffsverletzungen.
unicodestr brauche ich allerdings für die Sprachausgabe als einen string und nicht als Zeiger.Das Problem mit dem nicht funktinioeren außerhalb der Umgebung konnte ich lösen indem ich den Compiler oder so auf "Release" gestellt habe. Der steht sonst auf "Debug".
-
FreakySmiley schrieb:
Das Problem mit dem nicht funktinioeren außerhalb der Umgebung konnte ich lösen indem ich den Compiler oder so auf "Release" gestellt habe. Der steht sonst auf "Debug".
Ob das so gut ist, weiß ich nicht. Ich glaube beim Debug Modus wird der Speicherplatz immernoch schön vorinitialisiert. Bin mir da aber gerade nicht sicher.
Hmm, hab jetzt eigentlich versuchen wollen deinen Code anzupassen, wobei ich aber eher etwas verwirrt, bin weger der Klassen etc. Vllt. meldet sich noch jemand anderes.
Ein malloc gibt aber einen Zeiger auf Speicherbereich zurück, muss gecastet und dann in einen entsprechende Zeiger gespeichert werden.
& Referenzoperator
* DereferenzoperatorAlso vllt. so in etwa:
LPWSTR *unicodestr = (LPWSTR *)malloc(len); Iwas->Speaker(..., *unicodestr, ...);
-
Ist hier wohl nicht nötig, oder wie ist das zu verstehen das es so geht wie es ist.
Woran willst du den überhaupt anpassen?
-
Naja, es scheint noch zu Fehlern zu kommen, oder?
Persönlich bin ich ein wenig irritiert, dass das mit dem malloc so funktioniert. Vermute, dass da zu einem Laufzeitfehler führt, den du später mit Mühe und Not wieder suchen musst. Also, wenns so funzt und später nicht mehr, dann denk erstmal wieder an die Stelle mit dem malloc.
-
Tja, wo fängt man am besten an?
1. LPWSTR ist ein Zeiger!
2. malloc will als Parameter die Größe des zu reservierenden Speichers in Byte! len - der Parameter, den Du übergibst - ist laut Dokumentation zu MultiByteToWideChar aber nur die Anzahl der zu reservierenden Zeichen! Daraus folgt, dass Du viel zu wenig Speicher reservierst!Deshalb:
LPWSTR unicodestring = malloc(len * sizeof(WCHAR));
...
free(unicodestring);
...
Edit:
Für C++ muss natürlich das Ergebnis von malloc gecastet werden:
LPWSTR unicodestring = (LPWSTR)malloc(len * sizeof(WCHAR));in C++ könntest Du allerdings auch statt malloc/free new[]/delete[] benutzen ...
-
Im konkreten Fall, wo der Eingabestring ja scheinbar nie länger als 79 Zeichen sein darf, reicht auch ein
wchar_t unicodestr[80];
free() entfällt dann ersatzlos. Es muss dann aber natürlich sichergestellt sein, dass 79 Zeichen wirklich immer ausreichen!
Eine Aufstellung der Windows-Datentypen findet sich hier. Generell ist alles, was mit LP anfängt, im WinAPI ein Zeigertyp (LP = Long Pointer, LPWSTR = Long Pointer to Wide STRing. Das "Long" in "Long Pointer" ist ein Überbleibsel aus der Zeit, als zwischen Nah- und Fernzeigern unterschieden wurde und hat heute keine Bedeutung mehr).
Allerdings: Die Arbeit mit verschiedenen Zeichensätzen ist ein ziemliches Gefrickel. Sofern es dir vernünftig möglich ist, wäre es für den Umgang mit COM wahrscheinlich am einfachsten, das gleich mit wchar_t zu machen. Im konkreten Fall (ich hoffe, ich vertu mich jetzt nicht; ich hab hier kein Windows, um das zu testen):
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <sapi.h> int ausgabe(LPCWSTR input) { ISpVoice *pVoice = NULL; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); if(SUCCEEDED(hr)) { hr = pVoice->Speak(input, 0, NULL); pVoice->Release(); return TRUE; } return FALSE; } int main() { bool ende = false; // Der COM-ORB muss nur einmal pro Thread initialisiert und geschlossen // werden. Wahrscheinlich kann man auch ein SpVoice-Objekt mehrmals benutzen, // aber im SAPI kenne ich mich nicht aus, daher lasse ich das hier. if(FAILED(::CoInitialize(NULL)) { return -1; } do { // _kbhit-Prüfung ist hier nicht notwendig. Du willst ja eh auf einen // Tastendruck warten, also kann _getch() ruhig blockieren. char ch = _getch(); if(ch == '\0') ch = _getch(); switch(ch) { case 'k': puts ( "Taste K gedrueckt."); ausgabe(L"Taste K gedrueckt."); break; case 'm': puts ( "Taste M gedrueckt."); ausgabe(L"Taste M gedrueckt."); break; case VK_ESCAPE: ende = true; break; } } while(!ende); ::CoUninitialize(); system("PAUSE"); }
-
DaRe schrieb:
Naja, es scheint noch zu Fehlern zu kommen, oder?
Nein, gar keine. Selbst wenn ich alle Warnungen anzeigen lasse gibt es keine Warnungen. Also die Einstellung nach Level4 Warnstufe.
Naja bis auf iwas mit dem getchar und einer umwandlung von iwas in iwas.Belli schrieb:
Daraus folgt, dass Du viel zu wenig Speicher reservierst!
Das erklärt warum ich, um ein Problem zu lösen,
len=len*10;
unter die deklaration geschrieben habe.
@seldon: Danke das werde ich mal ausprobieren. Ich befürchte aber Probleme da ich variabeln in einen anderen String schreibe mit sprintf_s. Es gibt doch immer Probleme.
EDIT: Ja da gibts Probleme. Durch herumprobieren und googlen konnte ich das Problem noch nicht lösen. Hier der Code wie er jetzt aussieht:#include <stdio.h> #include <stdlib.h> #include <sapi.h> #include <time.h> #include <conio.h> int ausgabe(LPCWSTR input) { ISpVoice *pVoice = NULL; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); if(SUCCEEDED(hr)) { hr = pVoice->Speak(input, 0, NULL); pVoice->Release(); return TRUE; } return FALSE; } int main() { bool ende = false; LPCWSTR uhrzeit1[80]; // Der COM-ORB muss nur einmal pro Thread initialisiert und geschlossen // werden. Wahrscheinlich kann man auch ein SpVoice-Objekt mehrmals benutzen, // aber im SAPI kenne ich mich nicht aus, daher lasse ich das hier. if(FAILED(::CoInitialize(NULL))) { return -1; } do { // _kbhit-Prüfung ist hier nicht notwendig. Du willst ja eh auf einen // Tastendruck warten, also kann _getch() ruhig blockieren. char ch = _getch(); //Warnung: Konvertierung von 'int' in 'char'. Nachgucken warum. if(ch == '\0') ch = _getch(); //Warnung: Konvertierung von 'int' in 'char'. Nachgucken warum. switch(ch) { case 'k': puts ( "Taste K gedrueckt."); ausgabe(L"Taste K gedrueckt."); break; case 'm': puts ( "Taste M gedrueckt."); ausgabe(L"Taste M gedrueckt."); break; case 't': struct tm *newtime; time_t long_time; time( &long_time ); newtime = localtime( &long_time ); //Z.B.: printf("Uhrzeit = %d:%d:%d", newtime->tm_hour, newtime->tm_min, newtime->tm_sec); swprintf_s(uhrzeit1, "Es ist jetzt %d Uhr %d\0",newtime->tm_hour, newtime->tm_min); printf(uhrzeit1); ausgabe(uhrzeit1); swprintf_s(uhrzeit1, " und %d Sekunden.\n\0", newtime->tm_sec);//String geteilt übergeben, da es mit "malloc" zu Speicher-Zugriffsverletzungen kommt. Noch nicht geändert. printf(uhrzeit1); ausgabe(uhrzeit1); //Das Problem hat was mit Zahlen zu tun ... break; //Entscheiden ob Sekunden notwendig sind. case 'd': struct tm *newdate; time_t long_date; time( &long_date ); newdate = localtime( &long_date ); //Z.B.: printf("Uhrzeit = %d:%d:%d", newtime->tm_hour, newtime->tm_min, newtime->tm_sec); sprintf_s(uhrzeit1, "Heute ist der %d.%d.%d.\n\0",newdate->tm_mday, newdate->tm_mon+1, newdate->tm_year+1900); printf(uhrzeit1); ausgabe(uhrzeit1); break; case VK_ESCAPE: ende = true; break; } } while(!ende); ::CoUninitialize(); }
MfG
EDIT: Boah Leute! Dauernd bekomme ich Probleme mit inkompatiblen Typen. Was für eine Sprache ist denn das? Warum ist das so kompliziert gemacht? Bei mir gibts nur Zahlen und Buchstaben. Das sieht für mich aus als wenn immer wieder irgendein Problem aufkam, für dessen Lösung man ein weiteres Format benötigte und einbaute, bis am Ende 1024 verschiedene Formate vorhanden sind, von denen ICH eines nicht in das andere konvertiert bekomme...
"double ist nicht mit const char kompatibel"
"const char ist nicht mit LPCWSTR kompatibel"
"LPCWSTR ist mit garnichts kompatibel, ÄtschiBätch!"Ist hier in der IDE irgendwas falsch eingstellt? Kann sich denn nichts einfach mal so in etwas anderes konvertieren ...
-
Also, hier muss irgendwas falsch sein. Ich habe gerade Zwei Programme aus einem MS Visual c++ 2008 Projekt herauskopiert und versucht sie zu kompilieren.
Erstmal musste ich <stdlib.h> zu den includes schreiben damit er überhaupt "system("CLS")" erkennt. Früher reichten <stdio.h> und <string.h>
Dann meckert er bei strcat jetzt plötzlich: "Zu viele Argumente im Funktionsaufruf" obwohl das hier früher ohne Probleme ging: strcat(pos[ze], " ", zf++); (zf ist eine Zähl-variable)
Er kompiliert sie ja sogar ohne Warnungen deshalb, meckert aber in der IDE herum.
Dann musste ich Zähl-Variabeln ändern und aus sprintf-befehle Variabeln heraus holen, die darin mit 1 addiert werden und darunter schreiben, weil er sonst schon bevor er das was in der Variable steht in den String schreibt, sie mit 1 addiert.Und das bei zwei verschiedenen Programmen!
Heute erscheint mir manches allerdings Logisch, doch früher muss es auch ohne alle diese änderungen geklappt haben. Hat sich denn die Sprache verändert in der zeit von 2008 bis 2010?
Wie schlimm ist das erst wenn richtig Komplexe Programme sind ...
-
strcat erwartet 2 Parameter
strncat erwartet 3 ParameterDer erste Parameter ist auch noch ein Zeiger(sieht mir nach nem char aus)?
strcat(pos[ze], " ", zf++);
-
Ja, ist ein Zeiger.
while(zf!=zb) strcat(pos[ze], " ", zf++);
zf ist eine variabel, kein Parameter, die nur darin steht, damit ich diese {} Klammern nicht schreiben muss. Also wie da unten in dem einen Beispiel.
Es funktioniert ja so auch, aber warum gibt es keine Fehler wenn er denn schon meckert?Hier mal das andere etwas genauer:
Früher sah das so aus:if(zc<=9) sprintf(spa[zc], " %i", zc++); else sprintf(spa[zc], "%i", zc++);
Heute geht nur noch das:
if(zc<=9) { sprintf(spa[zc], " %i", zc); zc++; } else { sprintf(spa[zc], "%i", zc); zc++; }
Weil sonst, wie gesagt, schon zu früh zc um eins erhöht wird. Also im alten IDE:
zc=1, in das spa-Array wird auf Position 1 " 1" geschrieben.
Im Neuen IDE wird auf Position 1 schon " 2" geschrieben. DEshalb die Änderungen.
Das ist kein Codegemansche von mir, das ging früher wirklich so.Da muss isch doch was geändert haben. Aber egal.
Wie Löse ich das Problem ein Paar Posts weiter oben?
MfG
-
FreakySmiley schrieb:
Früher sah das so aus:
if(zc<=9) sprintf(spa[zc], " %i", zc++); else sprintf(spa[zc], "%i", zc++);
Heute geht nur noch das:
if(zc<=9) { sprintf(spa[zc], " %i", zc); zc++; } else { sprintf(spa[zc], "%i", zc); zc++; }
Das nehme ich dir nicht ab.
Je nachdem, wie spa und zc konkret definiert sind, muss dass jeder C Compiler übersetzen.
Schreibe mal ein eigenes main mit nur o.g. Code, übersetze dann und nenne die konkreten Compilerausgaben.
-
Hi,
was für Compilerausgaben willst du denn sehen? Zu dem Problem mit "sprintf" gibt es keine Compilerausgaben. Nur zu dem Problem mit "strcat".
Ich könnte den Code hier hin schreibenIch könnte mal den komletten alten Code, der früher funktioniert hat (Wo ich nur <stdlib.h> includiert habe damit diese "system" Aufrufe noch funktionieren.) und denk kompletten neuen Code hier reinschreiben, damit ihr das selbst testen könnt.
Aber das wird ein langer Post.
MfG
PS: Schon eine Idee zu dem Problem im Post vom 12:53:16 30.10.2011 ?