web-dev-qa-db-ja.com

C関数から文字列を返す

私は3年以上Cを使用していませんが、多くのことでかなり錆びています。

これは愚かに見えるかもしれませんが、現時点では関数から文字列を返すことはできません。次のことを前提にしてください:string.hは使用できません。

ここに私のコードがあります:

#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;
}

getStr関数を使用して文字列をキャプチャできますが、正しく表示できません(ガベージを取得します)。

ヘルプは大歓迎です。

29
MrWolf

呼び出し側のスタックに文字列を割り当て、関数に渡します。

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

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

または、getStrで文字列を静的にします。

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

または、ヒープに文字列を割り当てます。

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

これは良くない。関数が戻ると破棄される自動(スコープ指定)変数へのポインターを返しています。ポインターは破壊された変数を指したままになり、ほぼ確実に「奇妙な」結果(未定義の動作)を生成します。

malloc(例:char *rtnPtr = malloc(length))で文字列を割り当ててから、freeで後でmainに割り当てます。

8
nneonneo

スタックに文字列を割り当てて、それへのポインタを返しています。関数が戻ると、スタック割り当ては無効になります。ポインタは、次に関数が呼び出されたときに上書きされる可能性があるスタック上の領域を指すようになりました。

実行しようとしていることを実行するには、次のいずれかを実行する必要があります。

  1. mallocなどを使用してヒープにメモリを割り当て、そのポインターを返します。呼び出し元は、メモリの処理が完了したら、freeを呼び出す必要があります。
  2. 呼び出し関数(文字列を使用する関数)のスタックに文字列を割り当て、文字列を挿入する関数にポインターを渡します。呼び出し元関数の呼び出し全体の間、そのスタック上のデータは有効です。スタックに割り当てられたスペースを返すと、他の何かによって使用されるようになります。
3
Brian Campbell

ポインターが関数のローカル変数を指している。したがって、関数から戻るとすぐに、メモリの割り当てが解除されます。他の関数で使用するには、ヒープにメモリを割り当てる必要があります。

代わりにchar *rtnPtr = Word;

これを行うchar *rtnPtr = malloc(length);

メイン関数で利用できるように。使用後、メモリを解放します。

2
Arpit

Wordはスタック上にあり、getStr()が返るとすぐに範囲外になります。未定義の動作を呼び出しています。

1
John3136

Cythonの理解に取り組んでいるときに、このスレッドに出会いました。元の質問に対する私の拡張は、C/Cythonインターフェースで働いている他の人に役立つかもしれません。これは元の質問の拡張です:C関数から文字列を返し、CythonとPythonに利用できるようにする方法は?

Cythonでは、慣れていない人のために、高速化する必要があるPythonコードを静的に入力できます。したがって、プロセスはPython :)の作成を楽しみ、どこかで少し遅いことを見つけ、プロファイルを作成し、1つまたは2つの関数を分割して、それらを暗号化します。ワオ。 C速度に近い(Cにコンパイルされる)修正。わーい。もう1つの用途は、ここで行われているように、C関数またはライブラリをPythonにインポートすることです。

これは文字列を出力し、同じまたは別の文字列をPythonに返します。 cファイルc_hello.c、cythonファイルsayhello.pyx、cythonセットアップファイルsayhello.pyxの3つのファイルがあります。 python setup.py build_ext --inplaceを使用してコンパイルすると、pythonまたはipythonにインポートして関数sayhello.helloを実行できる共有ライブラリファイルが生成されます。

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

さらに簡単: strdup でmallocされた文字列へのポインターを返します。

#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