Ошибка компиляции структуры C

Почему следующий код вызывает ошибку времени компиляции? Кажется, я не понимаю, почему типы не совпадают.

typedef char f_string[MAX_CHARS+1] ;    /* string for each field */

/*
 * A parsed CSV line, with the number of fields and upto MAX_FIELDS themselves.
*/

typedef struct {
    int nfields ;               /* 0 => end of file */
    f_string field[MAX_FIELDS] ;        /* array of strings for fields */
} csv_line;

....

csv_line sut;
sut.field[0] = "Name, "; //Compile-time error.

Ошибка:

error: incompatible types in assignment

person Mike    schedule 06.12.2010    source источник


Ответы (5)


sut.field[0] is a char[MAX_CHARS+1]

"Name, " is a const char*

Попробуй это:

strcpy(sut.field[0], "Name, ");
person Ferruccio    schedule 06.12.2010
comment
Спасибо за вашу помощь. Принятие этого ответа, потому что это был самый быстрый выбор между другими. - person Mike; 06.12.2010

Вы пытаетесь присвоить const char * char[], что не совсем одно и то же. Это сработало бы, если бы ваш f_string был определен как

typedef const char * f_string;

То, что вы ищете здесь

strcpy ( sut.field[0], "Name, " );

Или используйте strncpy, чтобы можно было указать размер целевого буфера..

strncpy ( sut.field[0], "Name, ", MAX_CHARS )

Это убережет вас от переполнения вашего буфера.

person Will    schedule 06.12.2010
comment
strncpy() не является безопасным strcpy - он предназначен для обработки строковых полей фиксированной длины, которые не обязательно имеют завершающий нуль. - person caf; 06.12.2010
comment
Я не очень понимаю, что вы имеете в виду под безопасным strcpy. strncpy позволяет ограничить количество символов, копируемых в буфер назначения. Если вы установите максимальное количество символов меньше, чем размер целевого буфера, вы не будете переполнять его, если исходный буфер содержит строку, превышающую размер целевого буфера. Что произойдет, как мне напомнили, так это то, что у вас не будет завершающего нуля в буфере назначения; этот случай должен быть обработан и добавлен нуль. - person Will; 06.12.2010
comment
Правильно: он не добавляет завершающий '\0', если исходная строка слишком длинная; и если исходная строка короткая, она заполняет оставшуюся часть адресата (которая может быть довольно большой) с помощью '\0'. Поскольку с первым нужно справиться, это не замена strcpy(), как многие, кажется, верят. - person caf; 06.12.2010

Вам нужно будет использовать что-то вроде:

strcpy( sut.field[0],"Name, ");

Вы не можете назначать строки, как вы пробовали, кроме как в качестве инициализатора во время объявления.

person Michael Burr    schedule 06.12.2010

тип sut.field[0] — это массив символов размером MAX_CHARS+1 — вы не можете присвоить строковый указатель массиву символов.

Вам нужно либо изменить тип csv_line::field на const char*, либо просто сделать строковую копию литерала "Name" в целевой массив.

Обратите внимание, что и strcpy(), и strncpy() по отдельности небезопасны: первый может переполнить ваш буфер, а второй может оставить его без терминатора NUL. Вы должны знать об ОБОИХ этих обстоятельствах, даже если вы «знаете», что рассматриваемая строка никогда не переполнится.

Используйте вспомогательную функцию, чтобы сделать это безопасно:

char * strncopy(char *dst, const char *src, int dstsize)
{
    strncpy(dst, src, dstsize-1);
    dst[dstsize-1] = '\0';

    return dst;
}

Потом:

strncopy(sut.field[0], "Name, ", sizeof sut.field[0]);
person Steve Friedl    schedule 06.12.2010
comment
нет необходимости делать эту функцию; он уже существует: strncpy и IIRC, strcpyn на некоторых компиляторах. - person Will; 06.12.2010
comment
@Будет ли код для strncopy использовать strncpy внутри. OP добавляет функциональность к strncpy, которая гарантирует, что строка всегда завершается нулем. - person mgiuca; 06.12.2010
comment
в этом случае вообще не используйте strncpy и сделайте это самостоятельно с помощью простого цикла while и скопируйте char за char, не забывая добавлять нуль в конце. - person Will; 06.12.2010
comment
@Will - как бы ни было легко ошибиться в указателях, особенно ошибках, отличных друг от друга, вы бы предложили свернуть свои собственные, а не использовать известную и проверенную функцию? - person Steve Friedl; 06.12.2010
comment
все, что плавает в лодке - я обычно инициализирую свои буферы так, чтобы они сначала заполнялись нулями, а затем strncpy, давая ему на единицу меньше размера буфера в качестве максимального количества символов для копирования. есть несколько способов сделать это; просто предложил другое. - person Will; 06.12.2010
comment
Все, кроме явного завершения NUL, опасно, особенно при даче советов новичкам. - person Steve Friedl; 06.12.2010

Тип sut.field[0] действительно char [MAX_CHARS+1]. Однако большинство других ответов имеют тип "Name, " неправильно - на самом деле это тип char [7] (используйте sizeof "Name, " для простой демонстрации этого).

Тем не менее, вы по-прежнему не можете напрямую присвоить char [7] char [MAX_CHARS+1]. Вы даже не можете напрямую назначить char [7] другому char [7] (в этом случае инициализация обрабатывается иначе, чем назначение).

Ответ, вероятно, заключается в том, чтобы просто использовать функцию копирования - например, если вы уверены, что MAX_CHARS >= 6, вы можете просто использовать strcpy(). Если вы не можете быть уверены в правильности длины, вы можете использовать strncat() as в качестве усеченной копии строки:

sut.field[0][0] = '\0';
strncat(sut.field[0], "Name, ", MAX_CHARS);

(Обратите внимание, что, несмотря на название, strncpy() не для этого подходит и на самом деле очень редко вообще является желаемой функцией).


Однако стоит отметить, что вы можете косвенно назначать массивы (одного и того же типа), если они заключены в struct. Это означает, что следующее будет работать (если у вас есть компилятор C99):

typedef struct { char s[MAX_CHARS+1] } f_string;    /* string for each field */

csv_line sut;
sut.field[0] = (f_string){"Name, "};
person caf    schedule 06.12.2010
comment
+1 за strncat. Напоминаем, что strncpy не завершится, если источник больше адресата; забыл также, что strncat действительно завершает буфер назначения нулем. Я слишком долго работал с C++ std::string, поэтому я забыл некоторые нюансы строк C. - person Will; 06.12.2010