этот код, его работа в порядке и вернуть то, что я хочу, но он зависает, прежде чем напечатать его? - PullRequest
0 голосов
/ 27 марта 2010

я делаю эту программу ::

#include<stdio.h>

char *raw_input(char *msg);

main() {
char *s;
*s = *raw_input("Message Here Is: ");
printf("Return Done..");
printf(s);
}

char *raw_input(char *msg){
char *d;
    printf("%s", msg);
    scanf("%s",&d);
return d;
}

Для этого нужно распечатать мое сообщение и отсканировать ввод от пользователя, затем распечатать его, но в чем проблема при распечатке ввода от пользователя ???

Обновление ::

Мне нужна функция raw_input. звони так без всяких лишних

*s = *raw_input("Message Here");

Я не хочу использовать это ::

raw_input("Message Here Is: ", d);
....

Просто хочу вернуть строку, которую введет пользователь.

Update2 ::

от jamesdlin Ответ (Спасибо) ,, Теперь я понял, что моя проблема заключалась в том, как вернуть выделенную строку в этом:)

#include<stdio.h>
#define buffer 128

char *raw_input(char *msg);

main() {
char *s;
s = raw_input("Message Here Is: ");
printf("%s\n",s);
}

char *raw_input(char *msg){
char *d;
    printf("%s", msg);
    fflush(stdout);
    fgets(d, buffer, stdin); ## In this there is a problem
return d;
}

теперь, когда я запускаю эту программу, она печатает сообщение, а затем просто выходит из программы (завершает работу), не принимая никаких слов от пользователя ???

Ответы [ 6 ]

5 голосов
/ 27 марта 2010

Вы не выделяете память для d, поэтому использование ее в scanf приводит к неопределенному поведению.

На самом деле, это даже хуже: вы передаете адрес из d в scanf, который затем заполняется целым числом, считанным из консоли. По сути, вы инициализируете указатель целочисленным значением, поэтому указатель указывает куда-то в джунгли. Таким образом, разыменование это неопределенное поведение. [Обновить] : даже это еще не все: как @Heath указал ниже, это фактически позволяет вам повредить ваш стек вызовов, введя достаточно длинный ввод на консоли: - ((( [/ Update]

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

void raw_input(char *msg, char *d);

main() {
    char d[128];

    raw_input("Message Here Is: ", d);
    printf("Return Done..");
    printf(d);
}

void raw_input(char *msg, char *d){
    printf("%s", msg);
    scanf("%s", d);
}

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

Обновление: , поэтому вы хотите вернуть выделенную строку (то есть указатель char*) из raw_input() в любом случае. AFAIK у вас есть 3 варианта:

  • возвращает указатель, переданный вызывающей стороной в качестве параметра (небольшое расширение моего примера выше): это тот, который я бы предпочел. Однако для этого требуется дополнительный параметр функции (на самом деле 2, поскольку мы также должны передать длину буфера в правильном решении, чтобы избежать переполнения буфера). Поэтому, если вам абсолютно необходимо придерживаться подписи функции, показанной выше, это не вариант.
  • возвращает указатель на статический / глобальный буфер, видимый как для вызывающей, так и для вызываемой стороны : это вариант выше, чтобы избежать изменения сигнатуры функции. Недостатком является то, что код сложнее понять и поддерживать - вы не знаете, что функция изменяет статическую / глобальную переменную, фактически не глядя на ее реализацию. Это, в свою очередь, также затрудняет юнит-тестирование.
  • возвращает указатель на буфер, выделенный внутри функции - хотя технически это возможно, это худший вариант, поскольку вы фактически передаете владение буфером; другими словами, вызывающая сторона должна помнить, чтобы освободить возвращенный буфер. В простой программе, подобной той, которую вы показали выше, это может показаться не большой проблемой, но в большой программе этот буфер может быть передан в удаленные места в приложении, поэтому существует высокий риск того, что никто его не освободит. в конце концов, таким образом, утечка памяти.
2 голосов
/ 27 марта 2010

Как уже упоминалось, вы не выделяете память для использования с scanf. Но никогда не используйте scanf; это трудно использовать правильно и избежать переполнения буфера. Используйте fgets.

Из comp.lang.c FAQ: Почему все говорят, что не следует использовать scanf? Что я должен использовать вместо этого?

Кроме того, хотя этот фрагмент кода и не связан с вашей проблемой, он опасен:

*s = *raw_input("Message Here Is: ");
printf("Return Done..");
printf(s);

Вы передаете пользовательский ввод непосредственно в printf как строки формата, так что это восприимчиво к атакам форматной строки , если напечатанная строка содержит % символов. Лучше:

*s = *raw_input("Message Here Is: ");
printf("Return Done..");
printf("%s\n", s);

Кроме того, вам может понадобиться несколько новых строк при печати. Кроме того:

*s = *raw_input("Message Here Is: ");

не будет работать, потому что s ни на что не указывает, поэтому вы разыменовываете указатель мусора. Предполагая, что вы исправили raw_input, чтобы вернуть выделенную строку, оно должно быть:

s = raw_input("Message Here Is: ");

Наконец (также не имеет отношения к вашей проблеме):

char *raw_input(char *msg){
    char *d;
    printf("%s", msg);
    scanf("%s",&d);
    return d;
}

Вам следует позвонить fflush(stdout) после печати приглашения. См. Запросы моей программы и промежуточный вывод не всегда отображаются на экране, особенно когда я передаю вывод через другую программу.

2 голосов
/ 27 марта 2010
#include<stdio.h>

char *raw_input(char *msg);

int main() {
    char *s;
    s = raw_input("Message Here Is: ");
    printf("Return Done..");
    printf("%s", s);
    free(s);
    return 0;
}

char *raw_input(char *msg){
    char *d;
        d = malloc(20)
        if(d==0) return 0;
        printf("%s", msg);
        scanf("%19s", d);
    return d;
}

Попробуйте это, должно работать. Другие ответы указали на ваши ошибки, как я вижу ... Я был медленнее;)

РЕДАКТИРОВАТЬ: Хорошо, обнаружил ошибку ... исправил ее;)

EDIT2: Макс предположил, что структура возможна, вот код:

#include<stdio.h>

struct mystring{
    char str[20];
};

struct mystring raw_input(char *msg);

int main() {
    struct mystring input;
    input = raw_input("Message Here Is: ");
    printf("Return Done..");
    printf("%s", input.str);
    return 0;
}

struct mystring raw_input(char *msg){
    struct mystring input;
        printf("%s", msg);
        scanf("%19s", input.str);
    return input;
}
2 голосов
/ 27 марта 2010

Указатель d в функции не инициализирован. scanf будет заполнять произвольную память. Вместо этого вам нужно передать буфер (массив символов) для его заполнения, и буфер должен быть определен в main, в противном случае он будет уничтожен, прежде чем вы сможете его вернуть (если вы не выполните динамическое выделение, но это другое история).

1 голос
/ 27 марта 2010

Попробуйте этот эксперимент:

#include<stdio.h>

char *raw_input(char *msg);

main() {
    char *s;
    s = raw_input("Message Here Is: ");
    printf("Return Done..");
    printf(s);
}

char *raw_input(char *msg)
{
    int value = 0;
    char *d;
    printf("%s", msg);
    scanf("%s",&d);

    if (value)
        printf("value has become %08X\n", value);
    return d;
}

Выполните несколько экспериментов с входными сообщениями длиной до 3, 4, 5, 7, 8, 9, 11, 12, 13 и т. Д. Посмотрите, что результат для целочисленной переменной value. Вы увидите, что из-за неправильного использования scanf(), передав адрес d, вы разрешаете scanf() уничтожать локальные переменные вашей функции, включая адрес возврата.

И это возвращает нас к названию этого веб-сайта.

0 голосов
/ 27 марта 2010

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

попробуйте это: 1. создать переменную d в главной функции 2. и передать его в функцию raw_input

void raw_input(char *msg, char *d)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...