Подумайте об этом (объяснения последуют). Существуют большие различия между
char *string1 = "hello";
char *string2 = "world";
string1 = string2;
и
char string3[] = "hello";
char string4[] = "world";
strcpy(string3, string4);
и
char *string5 = "hello";
char *string6 = "world";
strcpy(string5, string6); /* WRONG */
и
char string7[] = "hello";
char string8[] = "world";
string7 = string8; /* VERY WRONG */
Убедитесь, что вы понимаете, как1/2 и 3/4 корпуса разные, но оба работают. Убедитесь, что вы понимаете, почему оба случая 5/6 и 7/8 являются неправильными и не будут работать (но по разным причинам).
Пояснения:
После
char string3[] = "hello";
char string4[] = "world";
у вас есть два массива, инициализированных в памяти, которые выглядят так:
+---+---+---+---+---+---+
string3: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+
+---+---+---+---+---+---+
string4: | w | o | r | l | d |\0 |
+---+---+---+---+---+---+
И после вызова
strcpy(string3, string4);
вы получите
+---+---+---+---+---+---+
string3: | w | o | r | l | d |\0 |
+---+---+---+---+---+---+
+---+---+---+---+---+---+
string4: | w | o | r | l | d |\0 |
+---+---+---+---+---+---+
strcpy
скопированные символы от array4
до array3
. (Обратите также внимание, что исходные string3
и string4
оказались одинаковой длины. Это также сработало бы, если бы string4
было короче, но если бы string4
было длиннее, был бы массивпереполнение при копировании в string3
.)
Теперь к регистру указателей. После
char *string1 = "hello";
char *string2 = "world";
у вас есть два анонимных массива, обычно в постоянной памяти, на которые указывают две переменные-указатели, которые выглядят так:
+-----------+ +---+---+---+---+---+---+
string1: | *----------->| h | e | l | l | o |\0 |
+-----------+ +---+---+---+---+---+---+
+-----------+ +---+---+---+---+---+---+
string2: | *----------->| w | o | r | l | d |\0 |
+-----------+ +---+---+---+---+---+---+
И затем после
string1 = string2;
указатели переставлены так:
+-----------+ +---+---+---+---+---+---+
string1: | * | | h | e | l | l | o |\0 |
+-----|-----+ +---+---+---+---+---+---+
|
+--------------+
|
V
+-----------+ +---+---+---+---+---+---+
string2: | *----------->| w | o | r | l | d |\0 |
+-----------+ +---+---+---+---+---+---+
Но у меня сложилось впечатление, что массивы char инициализируются как указатель (char * string, а не char char []) доступны только для чтения и не могут быть перезаписаны?
Верно. И это то, что идет не так в случае
char *string5 = "hello";
char *string6 = "world";
strcpy(string5, string6); /* WRONG */
. strcpy
пытается записать новые символы в string5
, что не удается, если указанная строка была сохранена в постоянной памяти. По той же причине вы не можете делать что-то вроде
string5[0] = 'H'; /* WRONG */