Массивы строк в Си - PullRequest
       27

Массивы строк в Си

1 голос
/ 17 сентября 2010

Мне нужно держать массив строк C. Теперь я знаю, что C-строки - это просто массив символов, поэтому, по сути, мне нужен 2-ой массив символов. Строки, которые я пытаюсь сохранить, также никогда не будут превышать 6 символов. Мой план состоит в том, чтобы инициализировать массив символов с 50 «слотами для строк», а затем, если я нажму 50 строк, перераспределить память массива, чтобы удвоить его емкость. Я пробовал что-то простое, как:

int main() {
    char strings[50][6];
    strings[0] = "test";
    printf("The string is: %s", strings[0]);
    return(0);
}

Но, когда я иду к его компиляции, я получаю следующую ошибку:

test.c: в функции «main»: test.c: 3: ошибка: несовместимые типы при присвоение типу 'char [6]' из типа ‘Char *’ test.c: 4: warning: несовместимое неявное объявление встроенная функция «printf»

Может ли кто-нибудь указывать на меня в правильном направлении?

Ответы [ 6 ]

5 голосов
/ 17 сентября 2010

strncpy(strings[0], "test", 6);, если ваша библиотека C не имеет strlcpy().Однако если вам необходимо изменить размер хранилища, лучше использовать char ** с malloc(), realloc() и free().

2 голосов
/ 17 сентября 2010

Невозможно назначить массивы напрямую таким образом.В вашем текущем случае вам нужно сделать что-то вроде ...

strcpy (strings[0], "test");

Хотя было бы более идиоматичным использовать массив указателей.Взгляните на p111 и далее K & R.

1 голос
/ 17 сентября 2010

Массив нельзя присвоить с помощью оператора =. Прежде всего, объект массива не может быть целью оператора присваивания ( Online C Standard, черновик n1256 , раздел 6.5.16.1, пункт 1). strings[0] - это объект массива типа char [6], поэтому он не может появиться в LHS оператора =.

Во-вторых, когда выражение массива не является операндом операторов sizeof или address-of & и не является строковым литералом, используемым для инициализации содержимого другого массива, тип выражения неявно преобразуется («распадается») из «массива N-элементов из T» в «указатель на T», а значением выражения является адрес первого элемента в массиве (раздел 6.3.2.1, параграф 3).

Строковый литерал «test» представляет собой 5-элементный массив char (const char в C ++) со статическим экстентом (это означает, что память для него выделяется при запуске программы и удерживается до выхода из программы). Однако, когда он появляется в выражении

strings[0] = "test";

его тип преобразуется из «5-элементного массива char» в «указатель на char», а его значение является адресом первого элемента, поэтому вы пытаетесь назначить указатель значение для объекта массива, который не является совместимым типом; плохое дзюю, сверх того, что он все равно не может назначить объект массива.

Если вы хотите скопировать содержимое одного массива в другой, вам нужно будет либо назначить каждый элемент массива индивидуально, например,

strings[0][0] = 't';
strings[0][1] = 'e';
strings[0][2] = 's';
strings[0][3] = 't';
strings[0][4] = 0;

или даже

size_t len = strlen("test");
size_t i;
for (i = 0; i < sizeof strings[0] - 1 && i < len; i++)
  strings[0][i] = "test"[i]; // yes, you can subscript a string literal
strings[0][i] = 0;

или используйте библиотечную функцию, например memcpy(), strcpy(), strncpy(), strcat(), sprintf() и т. Д.:

strcpy(strings[0], "test");

или

strncpy(strings[0], "test", sizeof strings[0] - 1); // -1 to leave room
                                                    // for 0 terminator
                                                    // if necessary  

или

sprintf(strings[0], "%*s", (int) sizeof strings[0] - 1, "test");

Обратите внимание, что вы можете инициализировать содержимое массива при его объявлении, например:

char foo[] = "test";      // foo is implicitly sized to 5 (+1 for 0 terminator)
int  bar[] = {1,2,3,4,5}; // again, size is implied from initializer

float f[3] = {1.0, 2.0, 3.0}; // Initializer cannot contain more items than 
                              // array is sized for

Я вижу, что идет веселая война за использование strcpy() против strncpy() в комментариях к другому ответу; моя позиция заключается в том, чтобы использовать тот, который соответствует данной ситуации. Если вы знаете, что ваши буферы достаточно велики для обработки максимально возможного ввода, используйте strcpy(). Если нет, используйте strncpy(), но имейте в виду, что вам, возможно, придется добавить терминатор 0 вручную.

1 голос
/ 17 сентября 2010

Сначала легкая часть. Вам нужно

#include <stdio.h>

чтобы избавиться от несовместимого предупреждения printf. Это связано с тем, как в стандарте написано, что C работает, что позволяет вам создать некоторую функцию, которая не похожа на стандартную printf, неявным объявлением этой функции с ее сигнатурой (неправильно) угаданной компилятором, и знанием компилятора что в то время как вы можете определить другой printf, вы, вероятно, на самом деле не имели в виду.

Хорошо, теперь более сложная часть. Массивы в Си немного особенные. Они могут вычислять литералы-указатели (которые нельзя назначить, что похоже на попытку 6 = 4;), или они могут вычислять весь массив, в зависимости от контекста. Обычно они являются литералами-указателями, но в этом случае strings[0] рассматривается как массив, поэтому вы получаете ошибку, а не то, что strings[0] является недопустимым l-значением (левое значение, означающее что-то, что может быть на левой стороне =). В любом случае вы не можете скопировать литерал указателя символа (который является тем, что "тест" оценивает) в массив. Когда вы делаете это в строке, где вы объявляете строку (массив символов), компилятор обрабатывает это по-разному, что может вызвать некоторую путаницу. В любом случае, вам нужно либо использовать strcpy для копирования символов, составляющих «тест», либо инициализировать строки [0] для «тестирования» следующим образом:

char strings[50][6] = { "test" };  // only initializes the first member of the array
1 голос
/ 17 сентября 2010

Используйте strncpy (если это возможно) или strcpy для вашего задания.

0 голосов
/ 17 сентября 2010

Проблема в том, что компилятор интерпретирует оператор char strings[50][6];

Вместо того, что вы надеялись, массив char с 50 слотами для строк 6 char, вы получилиchar массив одиночных char с измерениями 50x6.

Вместо char strings[50][6]; способ инициализации массива выглядит следующим образом (я знаю, как это сделать в куче, извините):

char ** strings[50] = malloc(50 * sizeof(char *));
for(int i = 0; i < 50; ++i)
{
    strings[i] = malloc(50 * 6 * sizeof(char *));
}

Незабудьте очистить после освобождения.

РЕДАКТИРОВАТЬ: И, как сказано выше.Перед вашим основным методом.Включите строку #include <stdio.h>.Здесь находится функция printf().

...