Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Что то не так с isspace();


Автор: lllJollyRogerlll 26.1.2015, 23:15
Не судите строго, но если считаете меня полным идиотом - можно прямо в лоб.
Ситуация такая - нужно решить задачку, она достаточно легкая(по крайней мере так написано на сайте, где я её нашел). Но у меня видимо не хватает мозгов для того что бы решить её. 
Вот суть:
Цитата

Исходные данные
Входной поток содержит набор целых чисел Ai (0 ≤ Ai ≤ 1018), отделённых друг от друга произвольным количеством пробелов и переводов строк. Размер входного потока не превышает 256 КБ.
Результат
Для каждого числа Ai, начиная с последнего и заканчивая первым, в отдельной строке вывести его квадратный корень не менее чем с четырьмя знаками после десятичной точки.

Я не хочу что бы вы за меня её решили, планирую сам разобраться. Для начала я решил поиграть со строками, а потом уже когда пойму что да как - перейду к вещественным числам. 
Итак, сейчас я написал немного кода, где создаю переменную, символьный массив, затем предлагаю пользователю инициализировать этот массив. Дальше - проверяю его, если идут символы - я копирую в массив, сохраненный в ДРП и так пока не встречается пробел, когда встречается пробел - указатель на строку отправляется в стек, и потом все по новой. В конце я вывожу это дело на экран и освобождаю стек. 
Звучит не плохо, но на деле не фурычит. Отладчиком проверяю - вылетает в 
Код
if (isspace(buffer[i]))
 этом месте, а что не правильно - понять не могу. В общем, если есть возможность - растолкуйте, вот код: 
Код

#include<iostream>
#include<Windows.h>
#include<stack>
#include<iomanip>

int main()
{
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    char buffer[300];
    char* pChar;
    bool is_space = false;

    std::stack<char*> myArray;
    std::cout << "Введите данные, отделенные пробелами: ";
    std::cin.getline(buffer, 300);

    for (int i = 0; i < strlen(buffer); i++)
    {
        
        if (isspace(buffer[i]))
        {
            if (!is_space)
            {
                myArray.push(pChar);
                pChar = 0;
                pChar = new char[30];
                is_space = true;
            }
            else continue;
        }
        else
        {
            pChar[i] = buffer[i];
            is_space = false;
        }
    }

    for (int i = 0; i < myArray.size(); i++)
    {
        std::cout << *myArray.top() << std::endl;
        delete myArray.top();
        myArray.pop();
    }

    return 0;
}

Спасибо!

Модератор: используй тег CODE только для кода. Для цитирования заданий или сообщений об ошибках лучше подходит QUOTE - не нарушается отображение форума на длинных строках.

Автор: baldina 27.1.2015, 00:33
Цитата(lllJollyRogerlll @  26.1.2015,  23:15 Найти цитируемый пост)
вылетает в if (isspace(buffer[i]))

определите buffer как unsigned char

Цитата(lllJollyRogerlll @  26.1.2015,  23:15 Найти цитируемый пост)
              
                myArray.push(pChar); // чему тут равно pChar?
                pChar = 0; // зачем обнулять перед присваиванием?
                pChar = new char[30]; // проще сделать stack<string>


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

int x;
while (...)
  cin>>x;
  // и не нужно проверок isspace, cin сам разберется


Цитата(lllJollyRogerlll @  26.1.2015,  23:15 Найти цитируемый пост)
std::cin.getline(buffer, 300);

так обработается всего одна строка (до '\n'), а не весь вход

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

Добавлено @ 00:35
Цитата(baldina @  27.1.2015,  00:33 Найти цитируемый пост)
так обработается всего одна строка (до '\n'), а не весь вход

кстати, если строка длиннее буфера, то в конце буфера вы, скорее всего, получите обрывок числа...

Добавлено @ 00:41
lllJollyRogerlll, если вы все еще хотите обрабатывать ввод вручную, вводите не по строкам, а посимвольно
Код

while ((c=cin.get()) != EOF) {
  if (!isspace(с))
     // добавить c к строке
  else {
     if (/*строка не пустая*/) {
       // добавить строку
       // обнулить строку
     }
  }
}

Автор: lllJollyRogerlll 27.1.2015, 10:21
Цитата(baldina @ 27.1.2015,  00:33)
              
                myArray.push(pChar); // чему тут равно pChar?

ну вот же, пока в строке не встречается пробел - в pChar записывается наш буфер, 
Код

 else
        {
            pChar[i] = buffer[i];
            is_space = false;
        }

а когда встречается пробел - ссылка на pChar(строку без пробелов) - передается в стек, потом освобождаем *pChar и создаем новую строку, с чистого листа, так сказать. Но если этот пробел идет после другого пробела,  is_space = true; - ничего не делаем, продолжаем цикл. Идея была такой... )
Код

 if (isspace(buffer[i]))
        {
            if (!is_space)
            {
                myArray.push(pChar);
                pChar = 0;
                pChar = new char[30];
                is_space = true;
            }
            else continue;
        }

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

Автор: baldina 27.1.2015, 10:39
Цитата(lllJollyRogerlll @  27.1.2015,  10:21 Найти цитируемый пост)
ну вот же, пока в строке не встречается пробел - в pChar записывается наш буфер, 

по крайней мере при первом вызове pChar может быть не инициализирован (если данные с пробела начинаются)

Цитата(lllJollyRogerlll @  27.1.2015,  10:21 Найти цитируемый пост)
даже компилироваться не хочет

да ну! http://ideone.com/kgnJ2y
и что говорит?
unsigned кстати можно поставить и в настройках компилятора.

Добавлено через 4 минуты и 4 секунды
lllJollyRogerlll, разделите свой код на части - хотя бы сделайте функцию чтения числа и функцию, пропускающую пробелы.
отлаживать будет проще.

Автор: lllJollyRogerlll 27.1.2015, 11:05
Цитата(baldina @ 27.1.2015,  10:39)

да ну! 
и что говорит?

http://dim.st/i66414.jpg

Автор: baldina 27.1.2015, 12:25
lllJollyRogerlll, забейте на unsigned (совет был неудачный; идея сводится к тому, что результат isspace определен только если вход лежит в опр. диапазоне), тут не в нем дело.
программа падает, потому что вы не инициализируете данные.
a) если первый символ - пробел, то в массив запихивается неинициализируемый указатель. это неправильно, но в месте вызова пока еще не страшно. однако в последующих вызовах
Код

pChar[i] = buffer[i];

приводит к краху, т.к. i может принимать значения до 299, а размер по адресу pChar - 30
б) если первый символ не пробел, то производится запись в pChar[0], а pChar указывает неизвестно куда. тут все падает. 

Автор: lllJollyRogerlll 27.1.2015, 15:40
Переписал, теперь у меня вылетает исключение вообще по каким то непонятным причинам, вот в этом месте:
Код

void Iterate_and_delete(std::stack<char*>& myArray)
{
    if (myArray.empty()) { return; }
    else
    {
        for (int i = 0; i < myArray.size(); i++)
        {
            std::cout << myArray.top() << std::endl;
            delete myArray.top();
            myArray.pop();
        }
    }
}

Вот код полностью:
Код

#include<iostream>
#include<Windows.h>
#include<stack>
#include<iomanip>

std::stack<char*>& foo(const char* const buffer, std::stack<char*>& Array);
void Iterate_and_delete(std::stack<char*>& Array);

int main()
{
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);

    char buffer[300];
    std::cout << "Введите данные, отделенные пробелами: ";
    std::cin.getline(buffer, 300);
    std::stack<char*> myArray;
    foo(buffer, myArray);
    Iterate_and_delete(myArray);
    
    return 0;
}

std::stack<char*>& foo(const char* const buffer, std::stack<char*>& myArray)
{
    bool is_space = false;
    char* ch = new char[300];
    int i = 0;
    int j = 0;
    for (i = 0, j = 0; i < strlen(buffer); i++)
    {
        if (isspace(buffer[i]))
        {
            if (!is_space)                                //прошлый символ - НЕ символ пробела?
            {
                ch[j] = '\0';                            //перед отправлением строки в стек, добавим символ завершения строки
                myArray.push(ch);                        
                ch = 0;
                ch = new char[300];
                j = 0;
                is_space = true;                        //прошлый символ - символ пробела!
            }
            else continue;                                //пробел не добавляем в стек
        }
        else
        {
            ch[j] = buffer[i];                            //копируем символы без пробелов из буфера во временную строку
            j++;
            is_space = false;
        }
    }
    ch[j] = '\0';
    myArray.push(ch);
    return myArray;
}

void Iterate_and_delete(std::stack<char*>& myArray)
{
    if (myArray.empty()) { return; }
    else
    {
        for (int i = 0; i < myArray.size(); i++)
        {
            std::cout << myArray.top() << std::endl;
            delete myArray.top();
            myArray.pop();
        }
    }
}

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

Автор: baldina 27.1.2015, 15:56
у меня работает (правда выкинул windows.h)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)