копирование входного потока в выходной (через scanf и printf)

Модератор: Модераторы разделов

Аватара пользователя
lolobot
Сообщения: 436
ОС: Gentoo 2008.0

копирование входного потока в выходной

Сообщение lolobot »

Код: Выделить всё

#include <stdio.h>

main()
{
char* c[0];

scanf("%s\n", c[0]);
printf("%s\n", c[0]);
}


Почемуто копирует только до первого пробела, а если пробелов нет - то не копирует. Где ошибся?

ps вроде %s - это строка, а значит пробелы должны учитываться.
GNU/Linux forever! [Gentoo 2008.0]
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: копирование входного потока в выходной

Сообщение serzh-z »

Вопрос только - куда копирует? -))

lolobot писал(а):
07.06.2008 15:40
Где ошибся?
В размере буфера.
Спасибо сказали:
Аватара пользователя
lolobot
Сообщения: 436
ОС: Gentoo 2008.0

Re: копирование входного потока в выходной

Сообщение lolobot »

serzh-z писал(а):
07.06.2008 16:00
Вопрос только - куда копирует? -))

lolobot писал(а):
07.06.2008 15:40
Где ошибся?
В размере буфера.

Что же тогда если не char?
GNU/Linux forever! [Gentoo 2008.0]
Спасибо сказали:
Аватара пользователя
azrael
Сообщения: 73
ОС: KUbuntu 8.04 Hardy Heron

Re: копирование входного потока в выходной

Сообщение azrael »

У вас массив из нуля символов.
Спасибо сказали:
Аватара пользователя
Dudraug
Сообщения: 313
ОС: Debian lenny/sid

Re: копирование входного потока в выходной

Сообщение Dudraug »

Ну во первых

Код: Выделить всё

#include <stdio.h>

main()
{
char c[20];

scanf("%s\n", c);
printf("%s\n", c);
}


Лучше так

Во вторых - scanf читает до пробела. даже если задана длина строки в спецификаторе.

в третьих без \n лучше будет;)

Код: Выделить всё

#include <stdio.h>

main()
{
char c[20];

scanf("%s", c);
printf("%s", c);
}


В четвертых для считывания пробелов имхо лучше использовать fgetc=)
P4-3.0, ASUS P5GD1, 1024MB OЗУ, GeForce 6600GT
Спасибо сказали:
Аватара пользователя
Iroln
Сообщения: 201
ОС: openSUSE 10.3

Re: копирование входного потока в выходной

Сообщение Iroln »

char* c[0];

Что это, инициализация массива? Вы хотели создать массив из нуля указателей? :rolleyes:

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

может так мм..? :happy:

Код: Выделить всё

#include <stdio.h>
#define SIZE 10

int main(void)
{
    char ch;
    int i;
    char c[SIZE];

    printf("Hу введите что-нибудь умное\n\n");
    for(i=0; i<(SIZE-1); i++) /* последний элементик сохраним для потомков :) */
    {
           ch = getchar();   /* считываем посимвольно из стандартного потока ввода*/
           putchar(ch);     /* дублируем ввод в стандартный поток вывода (это для прикола) */
           c[i] = ch;       /* заполняем массив символов (это не строка!) */
     }

    *(c + SIZE-1) = '\0';     /* делаем строку при желании (ну я думаю, вы понимаете связь между указателями и массивами?) */
                    /*  (помните, мы не тронули там последний элементик ( i<(SIZE-1) ), поэтому у нас он станет нулевым байтиком)*/

    printf("\n\nВы только что ввели: %s\n", c); /* теперь можно поглядеть в окончательном виде на плод своего безумства */
    return 0;
}


Код: Выделить всё

>Hу введите что-нибудь умное

I love programming
I love pr

Вы только что ввели: I love pr

Только надо учесть, что в в этом случае нам придется ввести все 9 элементов (10-й - это нулевой байт), и пока мы этого не сделаем, программа нас не опустит. Но зато мы никогда не введем символов больше, чем наш массив, и у нас никогда не будет переполнения буфера :)
Если бы мы доработали этот кусок кода, скажем вставили бы в него проверку на нажатие Enter, то он бы мог лечь в основу простой реализации функции ввода строк. Но все равно это очень дурацкий пример использования Си, безумство, одним словом.

А как надо?
Можно так:

Код: Выделить всё

#include <stdio.h>
#define SIZE 10  /* максимальная длина строки +1 байт */

int main(void)
{
    char str[SIZE];

    gets(str);   /* читаем строку */
    puts(str);   /* выводим строку */

    return 0;
}

Теперь мы можем ввести что захотим, а когда нажмем Enter получим распечатку того, что ввели. Но в этом случае мы не застрахованы от переполнения буфера, и злобный хакер сможет этим воспользоваться. Кстати, компилятор знает об этой особенности и пишет варнинг:
warning: the `gets' function is dangerous and should not be used.

что означает, что функция gets опасна и не должна использоваться ;)
Юниксойды давно съели на этой функции свою собаку. Поэтому используйте функцию fgets, которая принимает три аргумента, а именно первый - адрес по которому сохранять ввод, второй - целое число, которое определяет размер входной строки и третий - указатель на открытый поток (например файл).
В нашем случае это буквально будет выглядеть так:

Код: Выделить всё

fgets(str, 9, stdin);

stdin - это стандартный поток ввода, который открывается автоматически при запуске вашей программы.

Надеюсь, я популярно изложил кусочек теории о символьном и строковом вводе-выводе в Си?
Тайною мир держится
Спасибо сказали: