Как правильно инициализировать строку - PullRequest
1 голос
/ 26 июля 2011

Как мне определить следующую строку для следующей функции?

На данный момент я получаю предупреждение:

C4047: '=' : 'const char' differs in levels of indirection from 'char [4]'

и ошибка:

C2166: l-value specifies const object.

Оба в третьей строке кода ниже:

uint8_t *buffer= (uint8_t *) malloc(sizeof(uint32_t));
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
newval = protobuf_writeString (buffer, stringaling);

uint32_t protobuf_writeString(uint8_t *out,const char * str)
{

      if (str == NULL)
      {
          out[0] = 0;
          return 1;
      }
      else
      {
          size_t len = strlen (str);
          size_t rv = uint32_pack (len, out);
          memcpy (out + rv, str, len);
          return rv + len;
      }
}

Ответы [ 6 ]

4 голосов
/ 26 июля 2011
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";

Это недействительный код.Вы пытаетесь присвоить переменную const, что недопустимо.Затем вы пытаетесь присвоить массив символов персонажу.И, наконец, даже если у вас был неконстантный массив символов правильного размера, вы все равно не можете назначать массивы, поскольку они не являются первоклассными значениями.

2 голосов
/ 26 июля 2011

"fun" является строковым литералом, который по сути является const char *.

stringaling также const char *, поэтому ваша третья строка пытается присвоить const char * const char, который не будет летать.

Если это постоянная строка, вы можете просто сделать это:

const char *stringaling = "fun";

Если ваша входная строка динамическая, вы можете сделать это:

char *stringaling= (char *) malloc(strlen(inputString)+1);
strcpy(stringaling, inputString);

Очевидно, что если вы используете его неправильно, вам нужно освободить его или почувствовать гнев утечки памяти.

2 голосов
/ 26 июля 2011

Попробуйте использовать

char *stringaling = malloc(sizeof(uint32_t));
strcpy(stringaling, "fun");

... и посмотрите, не сработает ли это лучше. Обратите внимание, однако, что это довольно случайно, что (по крайней мере, обычно) sizeof(uint32_t) оказывается подходящим размером для «веселья». Обычно вы не хотите этого делать.

В качестве альтернативы вы можете захотеть:

char const *stringaling = "fun";

или

char stringaling[] = "fun";

Задание, которое вы получили, не будет работать - C имеет только очень самую минимальную поддержку строк, встроенных в язык; большинство операций (включая копирование строки) обычно выполняются с помощью библиотечных функций, таких как strcpy.

1 голос
/ 26 июля 2011

Если вы действительно хотите инициализировать char *, вы можете написать это вместо:

const char *stringaling = "fun";

А вот какая-то ссылка .

0 голосов
/ 27 июля 2011

Первая проблема:

const char *stringaling= (const char *) malloc(sizeof(uint32_t));

Несколько проблем на этой линии.

Прежде всего, вы не хотите объявлять stringaling как const char *; Вы не сможете изменить то, на что указывает stringaling (IOW, *stringaling не будет доступно для записи). Это важно, так как вы хотите скопировать содержимое другой строки в место, указанное stringaling. Удалите ключевое слово const.

Во-вторых, malloc(sizeof(uint32_t)) просто выделяет достаточно байтов (4) для этой конкретной строки, но не ясно, что вы подразумевали для выделения 4 байтов. При выделении памяти для массива (а строки - это массивы), явно укажите количество элементов , которые вы намереваетесь выделить.

Наконец, приведение результата malloc считается плохой практикой в ​​C. Приведение прекратит полезное диагностическое сообщение, если вы забудете включить stdlib.h или у вас нет прототипа для malloc в области видимости. Согласно стандарту 1989 года, malloc возвращает void *, который может быть назначен любому другому типу указателя объекта без необходимости приведения. Это не так в C ++, поэтому здесь требуется приведение, но если вы пишете C ++, вам все равно следует использовать new вместо malloc.

Итак, измените эту строку на

char *stringaling = malloc(LEN); // or malloc(LEN * sizeof *stringaling), but
                                 // in this case that's redundant since 
                                 // sizeof (char) == 1 

где LEN - количество символов, которые вы хотите выделить.

Общая форма для malloc звонка:

T *p = malloc (N * sizeof *p);

, где T - базовый тип (int, char, float, struct ... и т. Д.), А N - количество элементов типа T Вы хотите выделить. Поскольку тип выражения *p равен T, sizeof *p == sizeof(T); если вы когда-либо измените тип p, вам не нужно копировать это изменение в самом вызове malloc.

Вторая проблема:

*stringaling = "fun";

Опять же, есть несколько проблем в игре. Во-первых, вы не можете присваивать строковые значения с помощью оператора =. Строковые литералы являются выражениями массива, и в большинстве контекстов выражения массива имеют свой тип, неявно преобразуемый («распад») из «N-элементного массива T» в «указатель на T». Вместо того, чтобы копировать содержимое строкового литерала, вы просто назначаете указатель на первый символ в строке.

Что будет "работать" (см. Ниже), за исключением того, что вы разыменовываете stringaling в назначении; тип выражения *stringaling равен const char (char после внесения изменения, которое я указал выше), что несовместимо для присвоения с типом char *. Если вы отбросите оператор разыменования и напишите

stringaling = "fun";

вы бы исправили ошибку во время компиляции, но теперь у вас есть другая проблема; как уже упоминалось выше, вы не скопировали содержимое строкового литерала "fun" в блок памяти, выделенный с помощью malloc; вместо этого вы просто скопировали адрес строкового литерала в переменную stringaling. При этом вы теряете динамически распределяемый блок, что приводит к утечке памяти.

Чтобы скопировать строку содержимое из одного места в другое, вам нужно использовать библиотечную функцию, например strcpy или strncpy или memcpy, например:

strcpy(stringaling, "fun");

Если stringaling не нужно жить в куче (например, вы используете его только в одной функции и освобождаете его перед возвратом), вы можете полностью избежать управления памятью, объявив ее как обычный массив char и инициализируем его "fun":

char stringaling[] = "fun"; 

Это особый случай инициализации массива в объявлении, а не выражения присваивания, поэтому = делает копирование содержимого строкового литерала в массив stringaling. Однако это работает только в объявлении массива. Позже вы можете изменить массив с другими строковыми значениями (до 3 символов плюс терминатор 0), но вам придется снова использовать strcpy:

strcpy(stringaling, "one");

Если вам не нужно изменять содержимое stringaling, вы можете просто сделать

const char *stringaling = "fun";

Копирует адрес строкового литерала "fun" в переменную stringaling.И поскольку попытка изменить содержимое строкового литерала вызывает неопределенное поведение, мы do хотим объявить stringaling как const char * в этом случае;это предотвратит случайное изменение строкового литерала.

0 голосов
/ 27 июля 2011

без всего, что вы также можете использовать:

newval = protobuf_writeString (buffer, "fun" );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...