Как перенести const char * из функции в функцию? - PullRequest
4 голосов
/ 12 января 2020

Вот пример того, что я пытаюсь сделать:

#include <stdio.h>

FILE* f;
const char* getstring()
{
    f = fopen ("hello.txt", "r");
    char x[200];
    for (int i = 0; i < 200; i++) x[i] = 0;
    for (int c = getc(f), i = 0; (c != EOF) && (i < 200); c = getc(f), i++)
        x[i] = c;
    fclose(f);
    printf ("getstring(): x = %s", x);
    const char* y = x;
    printf ("getstring(): y = %s", y);
    return y;
}

void printstring (const char* string)
{
    printf ("%s", string);
}

int main()
{
    printstring(getstring());
    printf ("\nprintf: %s", getstring());
    return 0;
}

и вывод:

getstring(): x = Hello World
getstring(): y = Hello World
���getstring(): x = Hello World
getstring(): y = Hello World

printf: ��������

Я не знаю, почему функция printstring() ничего не выводится, а printf выводит случайные данные или почему в конце string есть немного случайных данных, когда я использую функцию printstring().

Есть ли способ исправить это и что я делаю не так?

Извините, если мой вопрос выглядит забавно, потому что я новичок в StackOverflow.com

Ответы [ 4 ]

6 голосов
/ 12 января 2020

Проблема

Проблема в том, что getstring() возвращает указатель на локальный массив. Этот массив разрушается, когда функция возвращается, поэтому у вас есть свисающий указатель. Использование этого указателя тогда является неопределенным поведением. Может произойти все, что угодно: например, вы можете получить случайное значение мусора, вы можете получить старое неизмененное значение, или система может получить sh.

Решение

Поскольку этот вопрос помечен как c ++, просто используйте std::string вместо char*, и этот вид кошмара навсегда исчезнет sh.

Обратите внимание, что для использования std::string в prinf() потребуется получить указатель с .c_str().

Если по непонятной причине вам необходимо использовать char*, вам придется использовать strdup() или выделить немного памяти для строки c и вернуть в нее указатель. Но вызывающая сторона должна затем удалить этот указатель, если вы не хотите, чтобы память просочилась.

3 голосов
/ 12 января 2020

Строка C сохраняется в локальном массиве функций. Этот массив уничтожается при выходе из функции. Поскольку вопрос помечен как C ++, используйте std :: string

#include <iostream>
#include <string>
#include <fstream>

std::string getstring()
{
    std::ifstream f("hello.txt");
    std::string x;
    x.resize(200);
    for (int i = 0; i < 200; i++) x[i] = 0;
    for (int c = f.get(), i = 0; (c != EOF) && (i < 200); c = f.get(), i++)
        x[i] = c;
    std::cout << "getstring(): x = " << x;
    const std::string& y = x;
    std::cout << "getstring(): y = " << y;
    return x;
}

void printstring (const std::string& string)
{
    std::cout << string;
}

int main()
{
    printstring(getstring());
    std::cout << "\nprintf: " << getstring();
    return 0;
}
0 голосов
/ 16 января 2020

Это ответ для C кода (не C ++). В коде ответа NPE на аналогичный вопрос, который я нашел на этой ссылке , которую я не нашел до публикации этого вопроса, я нашел malloc(bytes) Функция делает свое дело, но если вы компилируете с gcc, вам придется преобразовать функцию mallo c в char * вручную, используя (char*) malloc (bytes). Я также обнаружил, что, поскольку он использует указатели, вам придется обрабатывать выделенную строку как глобальную переменную, когда вы free() ее. Вот пример рабочего кода, основанного на коде в моем вопросе:

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

FILE* f;
char* getstring()
    {
    f = fopen ("hello.txt", "r");
    char* x = (char*) malloc (200);
    int length = 0;
    for (int i = 0; i < 200; i++) x[i] = 0;
    for (int c = getc(f), i = 0; (c != EOF) && (i < 200); c = getc(f), i++)
        { x[i] = c; length++; }
    fclose(f);
    return x;
    }

void printstring (char* string)
    {
    printf ("%s", string);
    free (string);
    }

int main()
    {
    printstring(getstring());
    return 0;
    }

И это выводит точные первые 200 байтов "hello.txt".

0 голосов
/ 12 января 2020

Так как другие объяснили как до go о решении проблемы, я немного расширю другие ответы и объясню почему у вас возникла проблема в первую очередь.

Проще говоря, всякий раз, когда вызывается функция, ей присваивается кадр стека (также называемый запись активации ). То есть: ему дается область памяти, в которую он может поместить свои локальные переменные. Когда функция возвращается, кадр стека уничтожается. Если затем вызвать другую функцию, кадр стека этой функции перезаписывает кадр стека предыдущей функции.

В этом конкретном c случае, когда getstring возвращает и printstring, а затем printf кадры стека последних двух вместе с кадром main перезаписывают данные, которые ранее находились в кадре стека getstring. Наиболее вероятным результатом является то, что printf выведет полный мусор. В худшем случае, это может сделать всю программу cra sh, если нулевой терминатор строки был перезаписан.

Интересно также отметить, что в вашем случае кажется, что двоичное значение, соответствующее этому из нулевого терминатора \0 был вставлен куда-то, потому что перед возвращением printf печатается только немного мусора. Это будет означать, что он не остановился на исходном нулевом терминаторе массива символов x, а скорее обнаружил значение, которое он интерпретировал как нулевой терминатор и возвратил.

Если вы используете sh, вы можете прочитать подробнее о стеке вызовов в Википедии .

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