Назначение символьной строки - PullRequest
0 голосов
/ 27 декабря 2011

Я работаю в среде Microsoft Visual Studio.Я обнаружил странное поведение

 char *src ="123";
 char *des ="abc";
 printf("\nThe src string is %c", src[0]);
 printf("\tThe dest string is %c",dest[0]);

 des[0] = src[0];

 printf("\nThe src string is %c", src[0]);
 printf("\tThe dest string is %c",dest[0]);

Результат:

1 a
1 a   

Это означает, что des[0] не инициализируетсяПоскольку src указывает на первый элемент строки.Я думаю, по правилам это должно работать.

Ответы [ 5 ]

3 голосов
/ 27 декабря 2011

Это неопределенное поведение:

des[0] = src[0];

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

char des[] ="abc";
1 голос
/ 27 декабря 2011

В C строковые литералы, такие как "123", хранятся как массивы char (const char в C ++). Эти массивы хранятся в памяти так, что они доступны в течение всего срока действия программы. Попытка изменить содержимое строкового литерала приводит к неопределенному поведению; иногда это будет «работать», иногда - нет, в зависимости от компилятора и платформы, поэтому лучше рассматривать строковые литералы как неписываемые.

Помните, что в большинстве случаев выражение типа "массив N-элементов из T" будет преобразовано в выражение типа "указатель на T", значением которого является местоположение первого элемента в массиве. ,

Таким образом, когда вы пишете

char *src = "123";
char *des = "abc";

выражения "123" и "abc" преобразуются из "3-элементного массива char" в "указатель на char", а src будет указывать на '1' в "123", а des будет указывать на 'a' в "abc".

Опять же, попытка изменить содержимое строкового литерала приводит к неопределенному поведению, поэтому когда вы пишете

des[0] = src[0];

компилятор может обрабатывать это утверждение любым способом, от которого он хочет: от полного его игнорирования до выполнения именно того, что вы ожидаете, от всего, что находится между ними. Это означает, что строковые литералы или указатель на них не могут использоваться в качестве целевых параметров для вызовов, таких как strcpy, strcat, memcpy и т. Д., А также не должны использоваться в качестве параметров для вызовов, таких как strtok.

1 голос
/ 27 декабря 2011

Раздел 2.13.4 ИСО / МЭК 14882 (Языки программирования - C ++) гласит:

  1. Строковый литерал - это последовательность символов (как определено в 2.13.2), заключенная в двойные кавычки, необязательно начинающиеся с буквы L, как в "..." или L "...". Строковый литерал, который не начинается с L, является обычным строковым литералом, также называемым узким строковым литералом. Обычный строковый литерал имеет тип «массив из n const char» и статическую длительность хранения (3.7), где n - это размер строки, как определено ниже, и инициализируется с помощью заданных символов. ...

  2. Все ли строковые литералы различны (то есть хранятся ли в неперекрывающихся объектах), определяется реализацией. Эффект попытки изменить строковый литерал: undefined .

1 голос
/ 27 декабря 2011

Поскольку src и des инициализируются строковыми литералами, их тип должен быть const char *, а не char *;как это:

const char * src ="123";
const char * des ="abc";

Никогда не было выделено памяти ни для одного из них, они просто указывают на предопределенные константы.Следовательно, оператор des[0] = src[0] является неопределенным поведением;вы пытаетесь изменить константу там!

Любой приличный компилятор должен фактически предупредить вас о неявном преобразовании из const char * в char * ...

Если вы используете C ++, рассмотрите возможность использованияstd::string вместо char * и std::cout вместо printf.

0 голосов
/ 27 декабря 2011

vinaygarg : Это означает, что des[0] не инициализируется. Поскольку src указывает на первый элемент строки. Я думаю, по правилам это должно работать.

Во-первых, вы должны помнить, что * src и * dst определены как указатели, ни больше, ни меньше.

Таким образом, вы должны спросить себя, что такое «123» и «abc» и почему их нельзя изменить? Короче говоря, он хранится в памяти приложения, которая read-only. Зачем? Строки должны храниться вместе с программой, чтобы они были доступны вашему коду во время выполнения, теоретически вы должны получить предупреждение компилятора о назначении неконстантного char* для const char *. Почему это read-only? Память для exe и dll должна быть каким-то образом защищена от перезаписи, поэтому она должна быть доступна только для чтения, чтобы не допустить ошибок и вирусов при изменении исполняемого кода.

Так как же вы можете получить эту строку в модифицируемую память?

// Copying into an array.
const size_t BUFFER_SIZE = 256;
char buffer[BUFFER_SIZE];
strcpy(buffer, "abc");
strncpy(buffer, "abc", BUFFER_SIZE-1);
...