Нарушение доступа к памяти. Что не так с этой, казалось бы, простой программой? - PullRequest
3 голосов
/ 18 ноября 2009

Это быстрая программа, которую я только что написал, чтобы узнать, вспомнил ли я, как запускать программу на С ++ с нуля. Он просто переворачивает строку (на месте) и выглядит в целом правильно для меня. Почему это не работает?

#include <iostream>
using namespace std;

void strReverse(char *original)
{
    char temp;
    int i;
    int j;
    for (i = 0, j = strlen(original) - 1; i < j; i++, j--)
    {
        temp = original[i];
        original[i] = original[j];
        original[j] = temp;
    }
}

void main()
{
    char *someString = "Hi there, I'm bad at this.";
    strReverse(someString);

}

Ответы [ 7 ]

15 голосов
/ 18 ноября 2009

Если вы измените это, то someString станет указателем на строковый литерал только для чтения:

char *someString = "Hi there, I'm bad at this.";

к этому, что делает someString модифицируемым массивом char, инициализируется из строкового литерала:

char someString[] = "Hi there, I'm bad at this.";

У вас должны быть лучшие результаты.

В то время как тип someString в исходном коде (char*) позволяет модифицировать char s, на которые он указывает, потому что он фактически указывает на строковый литерал (который не разрешается изменять) попытка выполнить любую модификацию с помощью указателя привела к тому, что технически известно как неопределенное поведение , что в вашем случае было нарушением доступа к памяти.

11 голосов
/ 18 ноября 2009

Если это не домашнее задание, тег C ++ требует, чтобы вы делали это с помощью стандартной библиотеки C ++:

std::string s("This is easier.");
std::reverse(s.begin(), s.end());

О, и это int main(), всегда int main(), черт возьми!

2 голосов
/ 18 ноября 2009

Линия

char *someString = "Hi there, I'm bad at this.";

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

char someString[] = "Hi there, I'm bad at this.";
2 голосов
/ 18 ноября 2009

Вы пытаетесь изменить строковый литерал - строку, размещенную в статическом хранилище.Это поведение не зависит (обычно происходит сбой программы).

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

char *someString = "Hi there, I'm bad at this.";
char* stringCopy = new char[strlen( someString ) + 1];
strcpy( stringCopy, someString );
strReverse( stringCopy );
delete[] stringCopy;//deallocate the copy when no longer needed
1 голос
/ 18 ноября 2009

См. Острый зуб для объяснения.

Попробуйте вместо этого:

#include <cstring>

void main()
{
    char someString[27];
    std::strcpy( someString, "Hi there, I'm bad at this." );
    strReverse( someString );
}

Еще лучше, забудьте о char * и используйте вместо него <string>. В конце концов, это C ++, а не C.

1 голос
/ 18 ноября 2009

Вы не можете изменять строковые литералы (статически размещенные). Чтобы делать то, что вы хотите, вам нужно использовать что-то вроде:

int main()
{
    char *str = new char[a_value];
    sprintf(str, "%s", <your string here>);
    strReverse(str);
    delete [] str;
    return 0;
}

[edit] strdup также работает, также strncpy ... я уверен, что есть множество других методов:)

0 голосов
/ 18 ноября 2009

При использовании более строгих настроек компилятора этот код даже не должен компилироваться:

char* str = "Constant string";

потому что оно должно быть постоянным:

const char* str = "Now correct";
const char str[] = "Also correct";

Это позволяет вам быстрее отлавливать эти ошибки. Или вы можете просто использовать массив символов:

char str[] = "You can write to me, but don't try to write something longer!";

Чтобы быть в полной безопасности, просто используйте std :: string. В конце концов, вы используете C ++, а обработка необработанных строк чрезвычайно подвержена ошибкам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...