#c #arrays #segmentation-fault
#c #массивы #ошибка сегментации
Вопрос:
У меня есть одномерный массив строковых литералов разной длины, например:
char *map[] = {
"ABC",
"ABCDEF",
...
};
Я хотел бы изменить определенный символ в массиве на map[y][x]='X';
, который не работает (и не должен) работать в соответствии с Википедией. Я также читал, что объявление его as char map[][]
исправит ошибку. Однако это ОЧЕНЬ большой массив, поэтому преобразование его в char map[][]
будет непрактичным. Есть ли другой способ выполнить то, что я хочу?
Комментарии:
1. если вы не возражаете потратить немного места, я бы согласился с ответом @VladfromMoscow. Это самый простой способ перенести ваш код.
2. @RSahu, ответ Влада работает, но при печати массива также выводится некоторый мусор (при печати).
Ответ №1:
#include <stdio.h>
#define CNV(x) (char []){ x }
int main(void){
char *map[] = {
CNV("ABC"),
CNV("ABCDEF"),
//...
};
map[1][2]='c';
printf("%sn", map[1]);//ABcDEF
return 0;
}
Комментарии:
1. На самом деле это лучше, чем ответ Влада, поскольку он позволяет мне его распечатать
Ответ №2:
Вы не можете изменять строковые литералы. Они неизменяемы в C / C .
Более правильное ваше определение массива будет выглядеть как
const char *map[] = {
"ABC",
"DEF",
...
};
Вы должны использовать двумерный массив символов, чтобы иметь возможность изменять его элементы.
Например
char map[][4] = {
"ABC",
"DEF",
...
};
Или вы могли бы использовать массив указателей, изменяя требуемый элемент, назначая ему новый строковый литерал.
Комментарии:
1. Я забыл упомянуть, что строки имеют разную длину.
2. @theunamedguy Смотрите мой обновленный пост. Примите во внимание, что нет никакой разницы, храните ли вы строки в массиве или храните указатели на строковые литералы, если все строковые литералы разные.
3. Это то, что я искал. 1
4. Однако, когда я пытаюсь его распечатать, он также печатает некоторый мусор.
5. @theunamedguy Вы не указали самый левый размер массива. Он должен быть достаточно большим, чтобы вместить каждый строковый литерал, включая его завершающий ноль. Смотрите определение двумерного массива в моем сообщении. Вы должны заменить значение 4 на фактический размер максимального строкового литерала.
Ответ №3:
Если вы хотите иметь возможность изменять строки, содержащиеся в вашем массиве, вам придется работать с динамически выделяемой памятью. Я бы выделил массив char*
, а затем прогнал и выделил память для каждого, за которым следует вызов strncpy
, или аналогичный.
char** ptrArray = malloc(sizeof(char*)*NUM_STRINGS);
...
ptrArray[0] = malloc(sizeof(someString)*sizeof(char));
strncpy(ptrArray[0], someString, sizeof(someString));
Это действительно зависит от контекста вашего приложения.
Комментарии:
1.
sizeof(char)
по определению1
.2. Это сработало бы, но потребовало бы инициализации всего массива при запуске.
3. Я всегда стараюсь поместить его туда. Я понимаю, что такое символ, но я не осознавал, что он является стандартным для всех компиляторов таким образом. Я никогда не сталкивался
sizeof(char) > 1
, но на всякий случай, я полагаю, я всегда включал его.4. @theunamedguy, это зависит от контекста вашего приложения. Вы всегда можете
realloc
, если вам нужно больше (или меньше, если вы осторожны) строк. Выделение памяти для каждого указателя и копирование данных, конечно, можно выполнить в любое время.5. @sherrellbc:
sizeof
фундаментально измеряется в единицахchar
. Оценкаsizeof(char)
похожа на вопрос: «Сколько метров в метре?»
Ответ №4:
Это массив указателей на строки, которые расположены в секции памяти, доступной только для чтения:
char* map[] =
{
"ABC",
"DEF",
...
};
Вы можете изменить значение каждого указателя, но вы не можете изменить содержимое указанной памяти.
Это массив указателей на строки, которые расположены в секции памяти для чтения / записи:
char map[][MAX_STR_LEN 1] =
{
"ABC",
"DEF",
...
};
Вы не можете изменить значение каждого указателя, но вы можете изменить содержимое указанной памяти.
Пожалуйста, обратите внимание, что во второй схеме у вас есть в основном два варианта:
-
Объявите массив как глобальную переменную, и в этом случае он будет находиться в разделе данных исполняемого образа и загружаться в память вместе с ним (т. Е. Код инициализации не выполняется).
-
Объявите массив как локальную переменную, и в этом случае функция будет включать дополнительный фрагмент кода для инициализации массива при каждом его вызове (копирование всех строк из RO-data-section в стек).
Ответ №5:
#include <stdio.h>
char s1[] = "abcd";
char s2[] = "efghi";
char s3[] = "jklmnop";
char *s[] = {
s1, s2, s3
};
int main(void)
{
s[0][0] = '$';
printf("%s %s %sn", s[0], s[1], s[2]);
return 0;
}
Редактировать: приведенный выше код заменяет указатель на строки указателем на (доступные для записи) массивы символов, что приводит к желаемому поведению, доступному для записи.