web-dev-qa-db-fra.com

Renvoi de la chaîne depuis la fonction C

Je n'ai pas utilisé C depuis plus de 3 ans, je suis assez rouillé sur beaucoup de choses.

Je sais que cela peut sembler stupide mais je ne peux pas renvoyer une chaîne d'une fonction pour le moment. Veuillez supposer que: je ne peux pas utiliser string.h pour cela. 

Voici mon 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;
}

Je peux capturer la chaîne (avec ma fonction getStr) mais je ne parviens pas à l’afficher correctement (j’ai des ordures).

L'aide est appréciée. 

22
MrWolf

Soit allouez la chaîne sur la pile côté appelant et transmettez-la à votre fonction:

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

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

Ou rendez la chaîne statique dans getStr:

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

Ou allouer la chaîne sur le tas:

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

Ce n'est pas bien. Vous retournez un pointeur sur une variable automatique (étendue), qui sera détruite au retour de la fonction. Le pointeur restera orienté vers une variable détruite, ce qui produira presque certainement des résultats "étranges" (comportement indéfini).

Vous devriez allouer la chaîne avec malloc (par exemple, char *rtnPtr = malloc(length)), puis free et la reporter plus tard dans main.

8
nneonneo

Vous allouez votre chaîne sur la pile, puis vous lui renvoyez un pointeur. Lorsque votre fonction revient, toute allocation de pile devient invalide. le pointeur pointe maintenant vers une région de la pile susceptible d'être écrasée lors du prochain appel d'une fonction.

Afin de faire ce que vous essayez de faire, vous devez effectuer l’une des opérations suivantes:

  1. Allouez la mémoire sur le tas en utilisant malloc ou similaire, puis renvoyez ce pointeur. L’appelant devra alors appeler free lorsque la mémoire sera utilisée.
  2. Allouez la chaîne sur la pile dans la fonction appelante (celle qui utilisera la chaîne) et transmettez un pointeur à la fonction dans laquelle placer la chaîne. Pendant tout l'appel de la fonction appelante, les données de sa pile sont valides. ce n'est que lorsque vous retournez que la pile allouée devient utilisée par autre chose.
2
Brian Campbell

Votre pointeur pointe vers la variable locale de la fonction. Ainsi, dès que vous revenez de la fonction, la mémoire est désallouée. Vous devez affecter de la mémoire sur le tas pour pouvoir l'utiliser dans d'autres fonctions.

Au lieu de cela char *rtnPtr = Word;

faites ceci char *rtnPtr = malloc(length);

Pour qu'il soit disponible dans la fonction principale. Après utilisation, libérez de la mémoire.

2
Arpit

Word est sur la pile et sort de la portée dès le retour de getStr(). Vous invoquez un comportement indéfini.

1
John3136

Je suis tombé sur ce fil en travaillant sur ma compréhension de Cython. Mon extension à la question initiale pourrait être utile à d’autres personnes travaillant à l’interface C/Cython. Il s’agit donc de l’extension de la question initiale: comment renvoyer une chaîne d’une fonction C en la mettant à la disposition de Cython et donc de Python?

Pour ceux qui ne le connaissent pas, Cython vous permet de taper de manière statique le code Python dont vous avez besoin pour accélérer. Le processus consiste donc à écrire Python :), à le trouver un peu lent quelque part, à le profiler, à supprimer une ou deux fonctions et à les cythoniser. Sensationnel. Vitesse proche de C (compile en C) Fixe. Yay. L'autre utilisation est d'importer des fonctions C ou des bibliothèques dans Python, comme cela est fait ici.

Ceci imprimera une chaîne et renverra la même chaîne ou une autre chaîne à Python. Il y a 3 fichiers, le fichier c_hello.c, le fichier cython sayhello.pyx et le fichier d'installation cython sayhello.pyx. Lorsqu'ils sont compilés à l'aide de python setup.py build_ext --inplace, ils génèrent un fichier de bibliothèque partagée pouvant être importé dans python ou ipython et la fonction sayhello.hello est exécutée.

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

Plus facile encore: renvoie un pointeur sur une chaîne qui a été mallocée avec strdup .

#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
Colin Weinshenker