2014-09-12 3 views
19

Я не использовал 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 функции), но я не могу получить его, чтобы правильно отобразить (я получаю мусор).

Справка приветствуется.

+1

Вы можете использовать 'ncurses.h', но не' string.h'? Какая странная среда ... – nneonneo

+2

Вы создаете массив переменной длины 'char word [length];' (** проблема безопасности **), затем присваиваете свой адрес 'rtnPtr' - функция завершает уничтожение локального массива символов' слово [длина] '. Вы возвращаете указатель на то, что перестает существовать. –

+0

@nneonneo: Это скорее предпосылка для этого задания. Я просто не должен использовать его для этого. – MrWolf

ответ

34

Либо выделить строку в стек на стороне вызывающего абонента и передать его в функцию:

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; 
} 
+1

если вы делаете malloc, вызывающий должен вызывать бесплатно на указателе для освобождения памяти – Ahmed

+0

Это глупый вопрос, но вам нужно вернуть строку, в которую передал вызывающий? Я изменяю его напрямую, поэтому я не понимаю, почему я должен вернуть его, не так ли? – MarcusJ

+1

Вы должны указать на недостаток второго подхода, который заключается в том, что статический буфер будет перезаписан при следующем вызове, поэтому метод не является потокобезопасным, а также дает неожиданные результаты даже в однопоточном коде, если пользователь заканчивает вызывая метод снова, все еще имея ссылку на первую строку. – BeeOnRope

7
char word[length]; 
char *rtnPtr = word; 
... 
return rtnPtr; 

Это не хорошо. Вы возвращаете указатель на автоматическую (облачную) переменную, которая будет уничтожена при возврате функции. Указатель будет указывать на уничтоженную переменную, которая почти наверняка произведет «странные» результаты (неопределенное поведение).

Вы должны выделить строку с malloc (например char *rtnPtr = malloc(length)), затем free ИНГ позже в main.

1

word находится в стеке и выходит за рамки, как только getStr() возвращается. Вы вызываете неопределенное поведение.

2

Вы назначаете свою строку в стеке, а затем возвращаете указатель на нее. Когда ваша функция вернется, любые распределения стека становятся недействительными; указатель теперь указывает на область в стеке, которая, вероятно, будет перезаписана при следующем вызове функции.

Для того, чтобы сделать то, что вы пытаетесь сделать, вам нужно выполнить одно из следующих действий:

  1. Выделение памяти в куче, используя malloc или подобное, затем возвращает этот указатель. Затем вызывающему абоненту необходимо позвонить free, когда это будет сделано с памятью.
  2. Выделите строку в стеке в вызывающей функции (той, которая будет использовать строку), и передайте указатель на функцию, чтобы вставить строку. Во время всего вызова вызывающей функции данные в его стеке действительны; его только после того, как вы вернете, что выделенное стекное пространство будет использовано чем-то другим.
2

Ваш указатель указывает на локальную переменную функции. Поэтому, как только вы вернетесь из функции, память освобождается. Вы должны назначить память на кучу, чтобы использовать ее в других функциях.

Вместо char *rtnPtr = word;

сделать это char *rtnPtr = malloc(length);

Так что он доступен в главной функции. После его использования освободите память.

0

Проще всего: верните указатель на строку, которая была центром oc'd с 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

Обычно это будет хорошо работать, но этот пользователь не может использовать 'string.h', а' strdup' является частью этого файла заголовка. –

0

Я столкнулся с этой проблемой, работая над своим пониманием Китона. Мое расширение исходного вопроса может быть полезным для других, работающих на интерфейсе C/Cython. Итак, это расширение исходного вопроса: как вернуть строку из C-функции, предоставляя ее Cython &, таким образом, Python?

Для тех, кто не знаком с этим, Cython позволяет вам статически вводить код Python, который вам нужно ускорить. Таким образом, процесс, наслаждайтесь написанием Python :), где-то его немного замедлите, проецируйте его, отпустите функцию или два и cythonize. Вау. Близко к скорости C (она компилируется на C) Исправлено. Ура. Другое использование - импорт C-функций или библиотек в Python, как это делается здесь.

Это напечатает строку и вернет ту же или другую строку в Python. Есть 3 файла, c файл c_hello.c, файл cython sayhello.pyx и файл настройки cython sayhello.pyx. Когда они скомпилированы с использованием 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 
) 
Смежные вопросы