2011-12-25 4 views
0

Часть большей программы, которую я создаю, требует наличия пути, который будет считываться из командной строки и хранится в классе. Поскольку пути могут быть произвольного размера и необходимы в нескольких функциях, я храню его в файле char* в файле заголовка. Но по какой-то причине, когда я присваиваю ему значение, программа segfaults.C++ глобальный указатель?

отладчик (GDB) показывает следующее:

Program received signal SIGSEGV, Segmentation fault. 
0x00007ffff7b4828a in std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char*)() 
    from /usr/lib/libstdc++.so.6 

Вот программа, которую я написал, чтобы показать проблему:

test.cpp:

#include "test.h" 

#include <iostream> 
#include <cstring> 

Test::Test() { 
    filepath = NULL; 
} 

void Test::set_path(char* string) { 
    char temp[strlen(string) + 1]; 
    strcpy(filepath, temp); 
} 

char * Test::get_path() { 
    return filepath; 
} 

int main(int argc, char *argv[]) { 
    std::cout << "Enter a file path: "; 
    char *temp; 
    std::cin >> temp; 
    Test *temp2 = new Test(); 
    temp2->set_path(temp); 
    std::cout << "Path: " << temp2->get_path() << std::endl; 
} 

test.h:

#ifndef TEST_H 
#define TEST_H 

class Test { 
private: 
    char *filepath; 

public: 
    Test(); 
    void set_path(char *); 
    char * get_path(); 
}; 

#endif // TEST_H 

Я не уверен, почему он падает. Что-то не так с методом, который я делаю? Кроме того, вместо того, чтобы просто переключиться на string, я хотел бы узнать больше об этой проблеме.

Заранее благодарен!

+0

"вместо того, чтобы просто переключиться на' string ', я хотел бы узнать больше об этой проблеме." Почему у вас аллергия на 'string'? –

+0

В конце концов я использовал 'std :: string' '. Я просто хотел выяснить, почему 'char *' s не работает. –

ответ

3

temp (внутри main) не инициализирован, и не указывает на любой действительный выделенный блок памяти, поэтому линия:

std::cin >> temp; 

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

  • Сделать tempchar[] и только для чтения в количестве символов, которые будут соответствовать в буфере.
  • Точка temp действительного буфера.
  • Еще не сделано, сделайте temp a std::string, и пусть класс std::string беспокоится об управлении памятью.


Вы также собираешься быть с аналогичной проблемой с filePath после исправления указанных выше проблем. filePath создается в NULL в Test конструктора, а затем вы копируете temp к блоку памяти, указываемой filePath в Test::set_path:

strcpy(filepath, temp); 

NULL относится к адресу, который вы не позволили разыменования. Вы должны изменить все свои C-строки на std::string s и использовать функции-члены std::string и перегруженные операторы для работы со строками на C++.

+0

Таким образом, решение должно состоять в том, чтобы сделать 'char' фиксированным размером (например, FILENAME_MAX) или использовать' std :: string'? –

+0

@ ChenXiao-Long: В C++, 'std :: string'. – AusCBloke

+0

Хорошо, я буду использовать 'std :: string'. Спасибо за ответ! –

1

Вы вызываете strcpy без выделения памяти для строки, которая должна быть скопирована в set_path. На странице руководства четко указано, что dest должен быть достаточно большим, чтобы содержать строку в src. Кроме того, вы копируете из пустого временного. Хотя, ваш сбой появляется раньше, когда вы читаете от cin в неинициализированный указатель.

Использование std::string.

#include <iostream> 

class Foo 
{ 
public: 
    Foo(const std::string& s) : s_(s) {} ; 
private: 
    std::string s_; 
}; 

int main() 
{ 
    std::string f; 
    std::cin >> f; 
    std::cout << f << std::endl; 
    Foo foo = Foo(f); 
    return 0; 
} 

Если вы действительно preffer то, что вы делаете:

class Foo 
{ 
public: 
    Foo(const char* s) { 
    size_t size = strlen(s); 
    s_ = new char[size + 1]; 
    // safer 
    strncpy(s_, s, size + 1); 
    } ; 
private: 
    char* s_; 
}; 

int main() 
{ 
    char buffer[1024]; 
    // be save 
    buffer[1023] = '\0'; 
    Foo foo = Foo(buffer); 
    return 0; 
} 

Второй пример еще сломана. Отсутствует надлежащий деструктор, конструктор копирования и оператор присваивания. Я оставлю это как упражнение.

+0

Спасибо вам за ответ! Я, вероятно, буду придерживаться 'std :: string', но я обязательно рассмотрю ваш второй метод как упражнение. –

0
Test::Test() { 
    filepath = NULL; 
} 

void Test::set_path(char* string) { 
    char temp[strlen(string) + 1]; 
    strcpy(filepath, temp); 
} 

Я не уверен, что вы думали, что strcpy собирался сделать, но то, что он делает копии с temp, который неинициализированным, чтобы filepath, что NULL. Поэтому ни один параметр не имеет никакого смысла.

Смежные вопросы