Строки в C: ловушки и методы

Я написал статью об этом:

Абстрактные классы и интерфейсы

Суммирование:

, Когда мы говорим об абстрактных классах, мы определяем характеристики типа объекта; определение , что объект .

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

10
задан Community 23 May 2017 в 12:09
поделиться

16 ответов

Это очевидно, но я думаю, важно знать, что строки не что иное больше, чем массив байтов, разделенных нулевым байтом. Строки C не так удобны для пользователя, как вы, наверное, знаете.

  • Запись нулевого байта где-нибудь в строке приведет к его усечению.
  • Выход за пределы обычно заканчивается плохо.
  • Никогда, никогда не используйте strcpy, strcmp, strcat и т. Д., Вместо этого используйте их безопасные варианты: strncmp , strncat, strndup, ...
  • Избегайте strncpy. strncpy не всегда будет ограничивать вашу строку нулями! Если исходная строка не помещается в целевой буфер, она обрезает строку, но не записывает нулевой байт в конец буфера. Кроме того, даже если исходный буфер намного меньше целевого, strncpy все равно перезапишет весь буфер нулями. Я лично использую strlcpy.
  • Не используйте printf (строка), вместо этого используйте printf ("% s", строка). Попробуйте подумать о последствиях, если пользователь вставит в строку% d.
  • Вы можете ' doStuff (s1); Вы должны сравнить каждый символ в строке. Используйте strcmp или лучше strncmp.
     если (strncmp (s1, s2, BUFFER_SIZE) == 0)
    doStuff (s1); 
26
ответ дан 3 December 2019 в 13:25
поделиться

Если возможно, используйте strlcpy (вместо strncpy) и strlcat.

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

#define strlcpy_sz(dst, src) (strlcpy(dst, src, sizeof(dst)))
0
ответ дан 3 December 2019 в 13:25
поделиться

Указатели и массивы, хотя и имеют схожий синтаксис, совсем не одно и то же. Дано:

char a [100]; char * p = a;

Для массива a нигде не хранится указатель. sizeof (a)! = sizeof (p), для массива это размер блока памяти, для указателя это размер указателя. Это становится важным, если вы используете что-то вроде: sizeof (a) / sizeof (a [0]). Кроме того, вы не можете ++ a, и вы можете сделать указатель указателем 'const' на символы 'const', но массив может быть только символом 'const', и в этом случае вы должны инициализировать его первым. и т. д. и т. п.

0
ответ дан 3 December 2019 в 13:25
поделиться

Я бы указал на подводные камни производительности из-за чрезмерной зависимости от встроенных строковых функций.

char* triple(char* source)
{
   int n=strlen(source);
   char* dest=malloc(n*3+1);
   strcpy(dest,src);
   strcat(dest,src);
   strcat(dest,src);
   return dest;
 }
0
ответ дан 3 December 2019 в 13:25
поделиться

Распространенная ошибка:

char *p;
snprintf(p, 3, "%d", 42);

она работает, пока вы не используете до sizeof (p) байт .. потом происходят забавные вещи (добро пожаловать в джунгли).

Объяснение

с помощью char * p вы выделяете место для хранения указателя ( sizeof (void *) bytes) в стеке. Правильнее всего здесь выделить буфер или просто указать размер указателя во время компиляции:

char buf[12];
char *p = buf;
snprintf(p, sizeof(buf), "%d", 42); 
0
ответ дан 3 December 2019 в 13:25
поделиться

Безопасность MySQL в PHP (или на любом другом языке в этом отношении) является широко обсуждаемой проблемой. Вот несколько мест, где вы можете получить полезные советы:

На мой взгляд, два наиболее важных элемента:

  • SQL-инъекция: Убедитесь, что вы экранировали все переменные вашего запроса с помощью PHP mysql_real_escape_string () функция (или что-то подобное).
  • Проверка ввода: Никогда не доверяйте вводу пользователя. См. и для обучения тому, как правильно дезинфицировать и проверять ваши входные данные.
0
ответ дан 3 December 2019 в 13:25
поделиться

возможно, вы могли бы проиллюстрировать значение часового '\ 0' следующим примером

char * a = "hello \ 0 world"; char b [100]; strcpy (б, а); printf (b);

Однажды у меня обгорели пальцы, когда я в своем рвении использовал strcpy () для копирования двоичных данных. В большинстве случаев это срабатывало, но иногда по загадочным причинам не удавалось. Тайна раскрылась, когда я понял, что двоичный ввод иногда содержит нулевой байт, и strcpy () на этом завершается.

1
ответ дан 3 December 2019 в 13:25
поделиться

Я бы обсудил, когда и когда не использовать strcpy и strncpy и что может пойти не так:

char *strncpy(char* destination, const char* source, size_t n);

char *strcpy(char* destination, const char* source );

Я бы также упомянул возвращаемые значения строковые функции ansi C stdlib. Например, спросите: «Пройдет ли этот оператор if или нет?»

if (stricmp("StrInG 1", "string 1")==0)
{
    .
    .
    .
}
1
ответ дан 3 December 2019 в 13:25
поделиться

strtok не потокобезопасный , поскольку он использует изменяемый частный буфер для хранения данных между вызовами; вы также не можете чередовать или аннулировать вызовы strtok .

Более полезной альтернативой является strtok_r , используйте его всякий раз, когда можете .

2
ответ дан 3 December 2019 в 13:25
поделиться

Я обнаружил, что Техника char buff [0] оказалась невероятно полезной. Подумайте:

struct foo {
   int x;
   char * payload;
};

vs

struct foo {
   int x;
   char payload[0];
};

см. https://stackoverflow.com/questions/295027

См. Значение и варианты по ссылке

1
ответ дан 3 December 2019 в 13:25
поделиться

путают strlen () с sizeof () при использовании строки:

char *p = "hello!!";
strlen(p) != sizeof(p)

sizeof (p) yield, во время компиляции - размер указателя (4 или 8 байтов), тогда как strlen (p) подсчитывает во время выполнения длину массива символов с завершающим нулем (7 в этом примере).

2
ответ дан 3 December 2019 в 13:25
поделиться

Варианты str n * в stdlib не обязательно завершают строку назначения нулем .

В качестве примера: из документации MSDN на ] strncpy :

Функция strncpy копирует начальное количество символов strSource в strDest и возвращает strDest. Если количество меньше или равно длина strSource, нулевой символ не добавляется автоматически к скопированная строка. Если счет больше чем длина strSource, строка назначения дополняется нулем до количества символов.

3
ответ дан 3 December 2019 в 13:25
поделиться

str [0] эквивалентно 0 [str] , или, в более общем смысле, str [i] равно ] i [str] и i [str] равно * (str + i) .

3
ответ дан 3 December 2019 в 13:25
поделиться

Следующие функции могут использоваться для реализации неизменяемого strtok :

strcspn(string, delimiters)
strspn(string, delimiters)

Первый находит первый символ в наборе переданных вами разделителей. второй находит первый символ , а не в наборе переданных вами разделителей.

Я предпочитаю их strpbrk , поскольку они возвращают длину строки, если они не могут соответствовать .

3
ответ дан 3 December 2019 в 13:25
поделиться

Злоупотребление strlen () значительно ухудшит производительность.

for( int i = 0; i < strlen( string ); i++ ) {
    processChar( string[i] );
}

будет иметь временную сложность не менее O (n 2 ), тогда как

int length = strlen( string );
for( int i = 0; i < length; i++ ) {
    processChar( string[i] );
}

будет иметь временную сложность не менее O (n). Это не так очевидно для людей, у которых не было времени подумать об этом.

5
ответ дан 3 December 2019 в 13:25
поделиться

kmm уже имеет хороший список. Вот вещи, с которыми у меня были проблемы, когда я начал кодировать C.

  1. Строковые литералы имеют собственный раздел памяти и всегда доступны. Следовательно, они могут быть, например, возвращаемым значением функции.

  2. Управление памятью строк, в частности, с помощью библиотеки высокого уровня (не libc). Кто отвечает за освобождение строки, если она возвращается функцией или передается в функцию?

  3. Когда следует использовать «const char *» и когда «char *». И что это говорит мне, если функция возвращает "const char *".

Все эти вопросы не так уж сложно выучить, но их трудно понять, если вы их не научите.

2
ответ дан 3 December 2019 в 13:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: