Проблема заключается в назначении
arr[i] = str;
Это не создает новую копию str
, вместо этого arr[i]
просто указывает на то место, куда указывает str
(который является первым элемент массива str
или &str[0]
). И если вы сделаете это для всех элементов arr
, тогда все элементы будут указывать на одно и то же место.
Если вы «нарисуете» его, это будет выглядеть примерно так:
+--------+
| arr[0] | --\
+--------+ \ +-----+
| arr[1] | ----+--> | str |
+--------+ / +-----+
| arr[2] | --/
+--------+
| arr[3] | --> ???
+--------+
| ...... |
+--------+
[arr[3]
и далее неинициализированные , они указывают на неопределенные местоположения]
Одно возможное (и простое) решение состоит в том, чтобы сделать arr
не массивом указателей, а массивом массивов:
char arr[10][10];
Теперь каждый элемент arr
является независимым массивом, который вы можете использовать в scanf
scanf("%9s", arr[i]);
[Обратите внимание на ограничение длины, добавленное в формат, чтобы не записывать за пределы массива]
Вторая попытка еще хуже, так как тогда вы используете неинициализированный указатель str
как место назначения для scanf
. Это означает, что scanf
запишет прочитанную строку в неопределенную ячейку памяти. Это приводит к неопределенному поведению .
И у него все еще есть та же проблема , что и в первой программе, где каждый из инициализированных указателей в arr
указывает туда же!
Когда вы используете строковые литералы вместо массива для str
, вы должны помнить, что в C все строковые литералы действительно являются независимыми массивами символов.
Это означает, что "Hello"
является массив из шести символов (включая нуль-терминатор), а "World"
- это другой массив , полностью независимый от любого другого массива.
Это означает, что arr[0]
будет указывать на первый символ массив для "Hello"
, arr[1]
и arr[2]
оба будут указывать на первый символ массива для "World"
.
Оба arr[1]
и arr[2]
будут указывать на одно и то же место потому что вы не изменяете str
между второй и третьей итерацией.