2010-02-04 4 views
3

Я хочу использовать указатели для изменения массива символов в C++. Мне было интересно, есть ли что-то, что я должен делать по-другому? Правильно ли я делаю это? Есть ли более эффективный способ достичь этого?Обратный C-стиль String? - C++

Моя маленькая программа:

int main () 
{ 
    char buffer[80]; 

    PrintHeader(); 

    cout << "\nString reversal program"; 
    cout << "\nType in a short string of words."; 
    cout << "\nI will reverse them."; 
    cout << "\n:"; 
    cin.getline(buffer, 79); 

    cout << "\nYou typed " << buffer; 
    reverse (buffer); 
    cout << "\nReversed: " << buffer; 

    cout << endl; 
    system("PAUSE"); 
    return 0; 

} 


void reverse(char* string) 
{ 
    char* pStart, *pEnd; 
    int length; 
    char temp; 

    length = strlen(string); 

    pStart = string; 
    pEnd = &string[length - 1]; 

    while(pStart < pEnd) 
    { 
     temp = *pStart; 
     *pStart = *pEnd; 
     *pEnd = temp; 
     pStart++; 
     pEnd--; 
    } 
} 
+1

У меня была такая же проблема, что и на собеседовании. – Void

+0

Я уверен, что этот вопрос является обманом: http://stackoverflow.com/questions/784417/reversing-a-string-in-c http://stackoverflow.com/questions/2124600/how-to- reverse-a-string-in-place-in-c-using-pointers –

ответ

9
void str_reverse(char *str) { 
    char *str_end = strchr(str, 0); 
    std::reverse(str, str_end); 
} 

если вы должны написать цикл,

void str_reverse(char *str) { 
    std::size_t len = std::strlen(str); 
    for (std::size_t index = 0; index != len/2; ++ index) { 
     std::swap(str[ index ], str[ len - index - 1 ]); 
    } 
} 

или, если, конечно, вы можете использовать C++ строка,

void str_reverse(std::string &str) { 
    std::reverse(str.begin(), str.end()); 
} 
+0

Ваш код цикла (второй) дает нарушение прав доступа при замене символов. Я тестировал его в Visual Studio. str - строка litearl, поэтому я не думаю, что вы можете ее изменить. –

+0

@erolyeniaras Ваш код добавил строковый литерал. В этом вопросе или в этом ответе нет ничего подобного. – Potatoswatter

+0

Я получаю сообщение об ошибке во втором решении: Исключение выбрано: нарушение доступа к записи. _Left был 0xC2F490. Если есть обработчик для этого исключения, программа может быть безопасно продолжена. – user2286810

1

Вы можете использовать std::swap(*pStart, *pEnd) вместо открытого кодирования свопа.

Черт возьми, вы могли бы просто использовать std::reverse(buffer, buffer + strlen(buffer)). Но я полагаю, что на самом деле не будет использовать указатели самостоятельно, и, учитывая это требование, все выглядит нормально.

Ну, на самом деле, крошечный нит: если length==0, то &string[length - 1] не указывает на массив символов и теоретически не является допустимым указателем.

0

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

void RevBuff(char* Buffer) 
{ 

int length = strlen(Buffer); 
char * CpBuff = _strdup(Buffer); 
for(int i = length -1, x = 0; i >=0 ; i--, x++) 
{ 
    Buffer[x] = CpBuff[i]; 
} 
free(CpBuff); 
} 

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

3

Предполагая, что вы не можете ничего, кроме строковых функций C использовать, я бы

  • избежать заранее объявляющие переменные в начале функция. Это требование nt из C (с стандартом 1990 года), но в C++ более идиоматично объявлять и инициализировать переменные, где вы их используете.

  • избегать выхода за пределы (декремент за начало строки), если строка пуста.

Так что-то вроде:

void reverse(char* string) 
{ 
    char* first = string; 
    char* last = string + strlen(string); 

    while(first < last) 
    { 
     --last; //avoids decrementing last beyond start of string if string is empty 
     char temp = *first; 
     *first = *last; 
     *last = temp; 
     ++first; 
    } 
} 
+0

Я получаю сообщение об ошибке: Исключение брошено: нарушение доступа к записи. первый был 0x137F490. Если есть обработчик для этого исключения, программа может быть безопасно продолжена. – user2286810

0

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

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

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

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

+0

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

+0

@visitor: да. Оптимизирующий компилятор может иногда путаться с чрезмерно сложным кодом и не угадать, что имел в виду автор, -> не удалось его оптимизировать. Однако это не правило, и слишком сложный код может смутить оптимизатор так же. Только с большим количеством навыков и знаний вы можете написать код более оптимальным, чем может быть оптимизатор. Поэтому нет смысла оптимизировать этот код вручную, потому что, скорее всего, вы закончите хуже, чем оставив его ясным, очевидным и простым. –