Array als Returnwert

Schnelle objektorientierte, kompilierende Programmiersprache.
mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Array als Returnwert

Beitrag von mfro » Mo Feb 03, 2014 6:49 pm

chris_1981_ hat geschrieben: Jetzt noch eine Frage:
Würdet ihr das "empfangenen" String array weiterverarbeiten?
Oder wie würdet ihr so etwas anfangen?

Vielen Dank!
Wenn ich mich recht erinnere, sind da nur die führenden Nummern "verdreht". Die anschließenden, nicht direkt lesbaren Strings resultieren aus dem 7-Bit Zeichensatz, der in 8 Bit "gepackt" wird. Übertragen wird das dann nicht als Binärdatenstrom, sondern umgewandelt in einen String aus Hexadezimalziffern.

Weil man für die 7->8-Bit-Wandlung ein wenig "Bitgefummel" braucht, würde ich erst mal den String als Hexadezimal-String parsen und in ein Byte-Array wandeln. Auf diesem Byte-Array kannst Du dann die Dekodierung und 7->8-Bit Wandlung machen (entweder in ein weiteres Byte-Array) oder direkt ausgeben.

Als erster Denkanstoß (ohne wirklich tiefgreifend drüber nachgedacht zu haben):

Code: Alles auswählen

int hex_to_bin(char *out_bin, char *in_hex) { ... }
int bin_to_hex(char *out_hex, char *in_bin) { ... }
int sept_to_oct(char *out_bin, char *in_bin) { ... }
int oct_to_sept(char *out_bin, char *in_bin) { ... } 
Die Funktionen würden jeweils die Anzahl an umgewandelten Zeichen zurückliefern (die gültige Länge des im ersten Parameter erzeugten Binär- bzw. Hex-Strings) oder eine negative Zahl, wenn ein Fehler auftrat.
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Array als Returnwert

Beitrag von cloidnerux » Mo Feb 03, 2014 7:33 pm

Um das ganze auf die Spitze zu treiben, soll ein Atmega 32 demnächst diese Aufgabe erledigen.
Klar, was mache ich dann hier, da wäre doch mikrocontroller.net besser geeignet.
Nicht unbedingt. Wir können dir mit Sicherheit weiterhelfen. Ich programmiere nun schon seit einigen Jahren AVR und andere Mikrocontroller, inzwischen auch Beruflich ;)
Würdet ihr das "empfangenen" String array weiterverarbeiten?
Oder wie würdet ihr so etwas anfangen?
Du hast da deinen String und die Protokollbeschreibung, die genau sagt welche Teile welches Format haben.
Was also gemacht werden muss ist diese Informationen zu extrahieren und in eine verwertbare Form gebracht werden.
Ich würde also die einzelnen Teile extrahieren und Konvertieren, dazu noch etwas Prüfen ob auch alles das richtige Format hat.
Wer hat Dich eigentlich zum Moderator gemacht?* :-D
Schlimm ist das, gleich rauswerfen :D
Aber egt wollte ich nur ein Konzept verdeutlichen und wollte nicht gleich die malloc und free Keule rausholen. Deswegen habe(wollte) ich noch dazu geschrieben, dass man sich bitte Pointer zu Gemüte führen sollte.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Onraku
Beiträge: 43
Registriert: Fr Sep 09, 2011 2:14 pm

Re: Array als Returnwert

Beitrag von Onraku » Mo Feb 03, 2014 7:42 pm

Klar, was mache ich dann hier, da wäre doch mikrocontroller.net besser geeignet.
Nicht unbedingt. Wir können dir mit Sicherheit weiterhelfen. Ich programmiere nun schon seit einigen Jahren AVR und andere Mikrocontroller, inzwischen auch Beruflich ;)
...Außerdem wird einem hier ernsthaft geholfen, und sei es sogar wenn man das vergessene Semikolon einfach nicht findet. Im erwähten Forum kommt man sich immer vor wie ein Fortuna D'dorf-Fan beim FC Köln... ;)

chris_1981_
Beiträge: 72
Registriert: Sa Jun 15, 2013 8:41 pm

Re: Array als Returnwert

Beitrag von chris_1981_ » Mo Feb 03, 2014 8:17 pm

Hallo,
Du hast da deinen String und die Protokollbeschreibung, die genau sagt welche Teile welches Format haben.
Was also gemacht werden muss ist diese Informationen zu extrahieren und in eine verwertbare Form gebracht werden.
Ich würde also die einzelnen Teile extrahieren und Konvertieren, dazu noch etwas Prüfen ob auch alles das richtige Format hat.
Genau das habe ich ja vor, eventuell nicht so elegant wie ihr, dazu fehlt mir das Know how, aber immerhin kenne ich die stellen, wo und wann ich an die Informationen aus dem String ran muss. Deshalb war die Idee, ich lese aus dem String Array die "wichtigen" Stellen aus und übergebe Sie meiner Funktion rev_string(), diese setzt die Zeichen um, damit ich zumindest einmal die Telefonnummern und auch das Datum etc. raus bekomme, danach habe ich die eigentliche Textnachricht zu decodieren, dazu benötige ich erst einmal noch ein wenig Gehirnschmalz - aber das wird auch schon gehen. <<-- Genau aus diesem Grund benötige ich das Wissen um ein Return Array.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Array als Returnwert

Beitrag von cloidnerux » Mo Feb 03, 2014 11:21 pm

...Außerdem wird einem hier ernsthaft geholfen, und sei es sogar wenn man das vergessene Semikolon einfach nicht findet. Im erwähten Forum kommt man sich immer vor wie ein Fortuna D'dorf-Fan beim FC Köln... ;)
Ich hatte da noch keine so schlimmen Erfahrungen :D
Man muss halt netter fragen, dort bedarf es keiner Anmeldung und jeder Depp stellt dort eine Frage à la "Ich bin zu faul für irgendwas, man möge mir bitte den Ar*** abwischen". Da wird man halt irgendwann ungehalten ;)
Genau das habe ich ja vor, eventuell nicht so elegant wie ihr, dazu fehlt mir das Know how, aber immerhin kenne ich die stellen, wo und wann ich an die Informationen aus dem String ran muss. Deshalb war die Idee, ich lese aus dem String Array die "wichtigen" Stellen aus und übergebe Sie meiner Funktion rev_string(), diese setzt die Zeichen um, damit ich zumindest einmal die Telefonnummern und auch das Datum etc. raus bekomme, danach habe ich die eigentliche Textnachricht zu decodieren, dazu benötige ich erst einmal noch ein wenig Gehirnschmalz - aber das wird auch schon gehen. <<-- Genau aus diesem Grund benötige ich das Wissen um ein Return Array.
Eine "standard" Lösung ist folgende:

Code: Alles auswählen

void doSomething(const char * baseString, char * result1)
Du bekommst einmal einen Pointer auf den zu verarbeitenden String und dann noch Pointer auf die Ergebnis-Arrays, damit übergibst du die Verantwortung den Speicher zu reservieren an denjenigen, der die Funktion aufruft.
Ein möglicher Aufruf sieht so aus:

Code: Alles auswählen

char text[80];     //Ein wenig Speicher reservieren
char result[80];     //Noch ein wenig speicher reservieren
getText(text);
doSomething(text, result);
Nun muss man aber einiges beachten. Die Funktion "doSomething" erhält Pointer, aus Sicht dieser Funktion weiß man nicht, ob das ein NULL-Pointer ist, ob da für 2 chars Speicher reserviert wurde oder für 10000.
Es gibt da Lösungen für, die sind aber gut genug im Wiki dokumentiert zum Thema Pointer und Speichermanagement.
Zudem musst du in der Funktion die Information haben, wie lang der String ist. Der "normale" Ansatz ist nach dem 0-Byte zu suchen, das einen validen C-String abschließt. Wenn du jedoch deine Strings falsch zusammen baust, kann passieren das du kein 0-Byte am Ende hast. In diesem Fall musst du der Funktion noch einen Parameter String-Länge übergeben.


Dann noch Konzeptuell:
Da man ein PDU quasi Zeichen für Zeichen auswerten muss, würde ich eine Zustandsmaschine bauen und dann Zeichen für Zeichen auswerten. Das würde sogar die Möglichkeiten bieten, in quasi Echtzeit den PDU auszuwerten, wenn dieser über eine langsame serielle Schnittstelle kommt(9600 Baud und co.)
Redundanz macht wiederholen unnötig.
quod erat expectandum

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Array als Returnwert

Beitrag von nufan » Di Feb 04, 2014 6:39 pm

Wenn du die Daten seriell verarbeitest, wäre meiner Meinung nach ein static Array auch eine akzeptable (und vor allem wenig umständliche) Lösung:

Code: Alles auswählen

char *const reverse_string( char const input[80] )
{
    static char reversed[80];
    // reversed[...] = ...;
    return reversed;
}
Dabei wird das Array nur ein einziges Mal angelegt und befindet sich immer an der gleichen Speicherstelle. Es wird auch nicht zerstört, wenn du die Funktion verlässt. Es ist also sicher einen Zeiger darauf zurückzugeben.

Das funktioniert, wenn du dein Array füllst, die Daten darin interpretierst und erst dann den nächsten Datensatz verarbeitest. Das kannst du machen, wenn kein Bedarf einer Daten-History besteht und ein einzelner Datensatz wirklich immer in einer Array-Größe Platz hat.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Array als Returnwert

Beitrag von Xin » Di Feb 04, 2014 11:03 pm

dani93 hat geschrieben:Wenn du die Daten seriell verarbeitest, wäre meiner Meinung nach ein static Array auch eine akzeptable (und vor allem wenig umständliche) Lösung:

Code: Alles auswählen

char *const reverse_string( char const input[80] )
{
    static char reversed[80];
    // reversed[...] = ...;
    return reversed;
}
Dabei wird das Array nur ein einziges Mal angelegt und befindet sich immer an der gleichen Speicherstelle. Es wird auch nicht zerstört, wenn du die Funktion verlässt. Es ist also sicher einen Zeiger darauf zurückzugeben.
Das ist korrekt für ein Einsteigerprogramm, wo man sich keine Gedanken über Multithreading machen muss. Ich setz das nur als (*) mal dran, diese Lösung verwende ich teilweise auch.

Warum gibst Du einen (char * const) zurück? Hat das const hier eine Bedeutung, die mir an der Stelle nicht bekannt ist?
Der (char * const) wird beim zuweisen kopiert, kann danach also in einem (char *) gespeichert werden. Oder möchtest Du auf ein (char const *) raus?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Array als Returnwert

Beitrag von nufan » Mi Feb 05, 2014 2:11 pm

Xin hat geschrieben:Warum gibst Du einen (char * const) zurück? Hat das const hier eine Bedeutung, die mir an der Stelle nicht bekannt ist?
Der (char * const) wird beim zuweisen kopiert, kann danach also in einem (char *) gespeichert werden. Oder möchtest Du auf ein (char const *) raus?
Naja jein. Ich könnte damit sagen, dass sich der Aufrufer einen Zeiger zum Beginn der Daten behalten muss (kann man natürlich auch umgehen, aber das muss dann schon explizit erfolgen). Das const war eigentlich willkürlich gesetzt, ich weiß zu wenig über den Programmablauf um das sinnvoll sagen zu können.

chris_1981_
Beiträge: 72
Registriert: Sa Jun 15, 2013 8:41 pm

Re: Array als Returnwert

Beitrag von chris_1981_ » Mi Feb 05, 2014 10:01 pm

Hallo zusammen,

ich habe nun endlich mal ein Ergebnis, jetzt ist die Frage: "Kann man das so machen?"
Es handelt sich um folgenden Code

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>

// my own header files
#include "str_length.h"


char* rev_string(char *string, char *new_string)
{
    int c = 0, i,s=0,length;
    char a, b;

    length = stringlength(string);

    for (i=0 ; i <= length; i++)
    {
        a = string[s];
        s++;
        b = string[s];
        s++;
        new_string[c] = b;
        c++;
        new_string[c] = a;
        c++;
    }
    return new_string;
}

char * pdu_sms_number(char *string, char *pdu_smsc)
{
    int pdu_length;
    int a = 0, i;

    pdu_length = stringlength(string);

    for (i=0; i<pdu_length; i++)
    {
        if (i >= 4 && i <= 16)
        {
            pdu_smsc[a] = string[i];
            a++;
        }
    }
    return pdu_smsc;
}

int main (int argc, char *argv[] )
{
    char pdu_string[160] = "0791947101670000040C9194214365879800003121911273324004D4F29C0E";
    char pdu_back[160]="";
    char pdu_sms_center[18] = "";

    // define pointer
    char *pdu_back_p = &pdu_back;
    char *pdu_sms_center_p = &pdu_sms_center;

    // become the pdu_string reverse back
    pdu_back_p = rev_string(pdu_string, pdu_back_p);

    // read the sms center number
    pdu_sms_center_p = pdu_sms_number(pdu_back_p, pdu_sms_center_p);

    // printout the information for
    // development
    printf ("complete pdu string %s \n", pdu_back_p);
    printf ("sms-center %s \n", pdu_sms_center_p);

    return 0;
}
Ich weiß, die for - Schleifen sollte ich gegen while-Schleifen austauschen, hierzu benötige ich noch ein bisschen Zeit für das Verständnis. ->> EOF und != '\0' usw. somit kann ich mir auch das strlen sparen.
Wo ich noch meine Probleme mit habe, ist die Art wie ich die Pointer erzeuge und zuweise. Ich weiß einige haben hier schon erläutert warum man 2 Pointer an die Funktion übergibt, ich finde es aber merkwürdig.

Zusätzlich bekomme ich folgende Warnungen vom Compiiler bei der Erzeugung von Pointer:
:123:24: Warnung: Initialisierung von inkompatiblem Zeigertyp [standardmäßig aktiviert]
:124:30: Warnung: Initialisierung von inkompatiblem Zeigertyp [standardmäßig aktiviert]
Es handelt sich hierbei um die Deklaration und Definition der Pointer.
Was mache ich falsch?

Vielen Dank und viele Grüße.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Array als Returnwert

Beitrag von cloidnerux » Mi Feb 05, 2014 11:16 pm

ich habe nun endlich mal ein Ergebnis, jetzt ist die Frage: "Kann man das so machen?"
Solange dein Compiler keine Fehler meldet, kann man das so machen.
Ich weiß einige haben hier schon erläutert warum man 2 Pointer an die Funktion übergibt, ich finde es aber merkwürdig.
Ein pointer zeigt auf die Daten, wenn du mit z.B

Code: Alles auswählen

pdu_smsc[a]
Daten in dein Array schreibst, dann schreibst du die irgendwo im Speicher, eben dahin wo pdu_smsc zeigt + a. Und deswegen übergibst du zwei pointer, mit dem ersten Teilst du mit, wo deine Ausgangsdaten sind, mit dem zweiten wo das Ergebnis gespeichert werden soll.
Und die Rückgabe des Pointers kannst du dir sparen, das macht bei dieser art Nutzung keinen sinn.
Es handelt sich hierbei um die Deklaration und Definition der Pointer.
Was mache ich falsch?
Nicht viel. Dein Compiler meldet nur, dass

Code: Alles auswählen

&pdu_back
einen anderen Typ hat als
char *pdu_back_p
Wenn ich mich recht erinnere, müsste es

Code: Alles auswählen

const char *pdu_back_p
sein.
Redundanz macht wiederholen unnötig.
quod erat expectandum

Antworten