web-dev-qa-db-de.com

String aus der C-Funktion zurückgeben

Ich habe seit über 3 Jahren kein C mehr verwendet, ich bin bei vielen Dingen ziemlich rostig.

Ich weiß, das mag dumm erscheinen, aber ich kann im Moment keine Zeichenfolge von einer Funktion zurückgeben. Bitte gehen Sie davon aus, dass ich string.h nicht verwenden kann. 

Hier ist mein Code: 

#include <ncurses.h>

char * getStr(int length)
{   
    char Word[length];

    for (int i = 0; i < length; i++)
    {
        Word[i] = getch();
    }

    Word[i] = '\0';
    return Word;
}

int main()
{
    char wordd[10];
    initscr();
    *wordd = getStr(10);
    printw("The string is:\n");
    printw("%s\n",*wordd);
    getch();
    endwin();
    return 0;
}

Ich kann die Zeichenfolge erfassen (mit meiner getStr-Funktion), aber ich kann sie nicht richtig anzeigen (ich bekomme Müll).

Hilfe wird geschätzt. 

22
MrWolf

Weisen Sie den String entweder auf der Seite des Anrufers auf dem Stack zu und übergeben Sie ihn an Ihre Funktion:

void getStr(char *wordd, int length) {
    ...
}

int main(void) {
    char wordd[10 + 1];
    getStr(wordd, sizeof(wordd) - 1);
    ...
}

Oder machen Sie den String in getStr statisch:

char *getStr(void) {
    static char wordd[10 + 1];
    ...
    return wordd;
}

Oder ordnen Sie die Zeichenfolge auf dem Heap zu:

char *getStr(int length) {
    char *wordd = malloc(length + 1);
    ...
    return wordd;
}
45
michaelmeyer
char Word[length];
char *rtnPtr = Word;
...
return rtnPtr;

Das ist nicht gut. Sie geben einen Zeiger auf eine automatische (bereichsabhängige) Variable zurück, die bei der Rückkehr der Funktion zerstört wird. Der Zeiger wird auf eine zerstörte Variable verweisen, die mit großer Wahrscheinlichkeit zu "merkwürdigen" Ergebnissen führt (undefiniertes Verhalten).

Sie sollten die Zeichenfolge mit malloc zuweisen (z. B. char *rtnPtr = malloc(length)) und dann freeing später in main.

8
nneonneo

Sie ordnen Ihre Zeichenfolge dem Stapel zu und geben dann einen Zeiger darauf zurück. Wenn Ihre Funktion zurückkehrt, werden alle Stapelzuweisungen ungültig. Der Zeiger zeigt nun auf einen Bereich auf dem Stapel, der beim nächsten Aufruf einer Funktion wahrscheinlich überschrieben wird.

Um das zu tun, was Sie versuchen, müssen Sie einen der folgenden Schritte ausführen:

  1. Weisen Sie mit malloc oder ähnlichem Speicher auf dem Heap zu, und geben Sie diesen Zeiger zurück. Der Aufrufer muss dann free aufrufen, wenn der Speicher abgeschlossen ist.
  2. Weisen Sie den String in der aufrufenden Funktion auf dem Stack zu (derjenige, der den String verwendet), und übergeben Sie einen Zeiger an die Funktion, in die der String eingefügt werden soll. Während des gesamten Aufrufs der aufrufenden Funktion sind die Daten in ihrem Stack gültig. Erst wenn Sie diesen Stack zurückgeben, wird er von etwas anderem verwendet.
2
Brian Campbell

Ihr Zeiger zeigt auf die lokale Variable der Funktion. Sobald Sie von der Funktion zurückkehren, wird der Speicher freigegeben. Sie müssen Speicher auf dem Heap zuweisen, um ihn für andere Funktionen zu verwenden.

Stattdessen char *rtnPtr = Word;

mach das char *rtnPtr = malloc(length);

Damit steht es in der Hauptfunktion zur Verfügung. Nachdem es benutzt wurde, wird der Speicher freigegeben.

2
Arpit

Word ist auf dem Stack und verlässt den Gültigkeitsbereich, sobald getStr() zurückkehrt. Sie rufen ein undefiniertes Verhalten auf.

1
John3136

Ich bin auf diesen Thread gestoßen, als ich an meinem Verständnis von Cython arbeitete. Meine Erweiterung der ursprünglichen Frage könnte für andere Benutzer von C/Cython von Nutzen sein. Dies ist also die Erweiterung der ursprünglichen Frage: Wie gebe ich einen String aus einer C-Funktion zurück, damit er Cython und damit Python zur Verfügung steht?

Für diejenigen, die sich nicht damit auskennen, können Sie in Cython Python-Code statisch eingeben, den Sie beschleunigen müssen. Also ist der Prozess, viel Spaß beim Schreiben von Python :), finde es irgendwo etwas langsamer, profiliere es, kalb ein oder zwei Funktionen ab und zykloniere sie. Beeindruckend. Nahe der C-Geschwindigkeit (kompiliert zu C) Behoben. Yay. Die andere Verwendung besteht darin, C-Funktionen oder -Bibliotheken wie hier beschrieben in Python zu importieren.

Dadurch wird eine Zeichenfolge gedruckt und dieselbe oder eine andere Zeichenfolge an Python zurückgegeben. Es gibt 3 Dateien, die c-Datei c_hello.c, die Cython-Datei sayhello.pyx und die Cython-Setup-Datei sayhello.pyx. Wenn sie mit python setup.py build_ext --inplace kompiliert werden, generieren sie eine gemeinsam genutzte Bibliotheksdatei, die in Python oder ipython importiert werden kann und die Funktion sayhello.hello ausgeführt wird.

c_hello.c

#include <stdio.h>

char *c_hello() {
  char *mystr = "Hello World!\n";
  return mystr;
  // return "this string";  // alterative
}

sayhello.pyx

cdef extern from "c_hello.c":
    cdef char* c_hello()

def hello():
    return c_hello()

setup.py

from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize


ext_modules = cythonize([Extension("sayhello", ["sayhello.pyx"])])


setup(
name = 'Hello world app',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
0
John 9631

Einfacher noch: Bringen Sie einen Zeiger auf einen String zurück, der mit strdup malloc'd wurde.

#include <ncurses.h>

char * getStr(int length)
{   
    char Word[length];

    for (int i = 0; i < length; i++)
    {
        Word[i] = getch();
    }

    Word[i] = '\0';
    return strdup(&Word[0]);
}

int main()
{
    char wordd[10];
    initscr();
    *wordd = getStr(10);
    printw("The string is:\n");
    printw("%s\n",*wordd);
    getch();
    endwin();
    return 0;
}
0