Я написал статью об этом:
Абстрактные классы и интерфейсы
Суммирование:
, Когда мы говорим об абстрактных классах, мы определяем характеристики типа объекта; определение , что объект .
, Когда мы говорим об интерфейсе и определяем возможности, которые мы обещаем обеспечить, мы говорим об установлении контракта приблизительно , что может сделать объект.
Это очевидно, но я думаю, важно знать, что строки не что иное больше, чем массив байтов, разделенных нулевым байтом. Строки C не так удобны для пользователя, как вы, наверное, знаете.
если (strncmp (s1, s2, BUFFER_SIZE) == 0)
doStuff (s1);
Если возможно, используйте strlcpy (вместо strncpy) и strlcat.
Еще лучше, чтобы сделать жизнь немного безопаснее, вы можете использовать такой макрос, как:
#define strlcpy_sz(dst, src) (strlcpy(dst, src, sizeof(dst)))
Указатели и массивы, хотя и имеют схожий синтаксис, совсем не одно и то же. Дано:
char a [100]; char * p = a;
Для массива a нигде не хранится указатель. sizeof (a)! = sizeof (p), для массива это размер блока памяти, для указателя это размер указателя. Это становится важным, если вы используете что-то вроде: sizeof (a) / sizeof (a [0]). Кроме того, вы не можете ++ a, и вы можете сделать указатель указателем 'const' на символы 'const', но массив может быть только символом 'const', и в этом случае вы должны инициализировать его первым. и т. д. и т. п.
Я бы указал на подводные камни производительности из-за чрезмерной зависимости от встроенных строковых функций.
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;
}
Распространенная ошибка:
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);
Безопасность MySQL в PHP (или на любом другом языке в этом отношении) является широко обсуждаемой проблемой. Вот несколько мест, где вы можете получить полезные советы:
На мой взгляд, два наиболее важных элемента:
mysql_real_escape_string ()
функция (или что-то подобное). возможно, вы могли бы проиллюстрировать значение часового '\ 0' следующим примером
char * a = "hello \ 0 world"; char b [100]; strcpy (б, а); printf (b);
Однажды у меня обгорели пальцы, когда я в своем рвении использовал strcpy () для копирования двоичных данных. В большинстве случаев это срабатывало, но иногда по загадочным причинам не удавалось. Тайна раскрылась, когда я понял, что двоичный ввод иногда содержит нулевой байт, и strcpy () на этом завершается.
Я бы обсудил, когда и когда не использовать 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)
{
.
.
.
}
strtok
не потокобезопасный , поскольку он использует изменяемый частный буфер для хранения данных между вызовами; вы также не можете чередовать или аннулировать вызовы strtok
.
Более полезной альтернативой является strtok_r
, используйте его всякий раз, когда можете .
Я обнаружил, что Техника char buff [0]
оказалась невероятно полезной.
Подумайте:
struct foo {
int x;
char * payload;
};
vs
struct foo {
int x;
char payload[0];
};
см. https://stackoverflow.com/questions/295027
См. Значение и варианты по ссылке
путают strlen ()
с sizeof ()
при использовании строки:
char *p = "hello!!";
strlen(p) != sizeof(p)
sizeof (p)
yield, во время компиляции - размер указателя (4 или 8 байтов), тогда как strlen (p)
подсчитывает во время выполнения длину массива символов с завершающим нулем (7 в этом примере).
Варианты str
n
*
в stdlib не обязательно завершают строку назначения нулем .
В качестве примера: из документации MSDN на ] strncpy
:
Функция strncpy копирует начальное количество символов strSource в strDest и возвращает strDest. Если количество меньше или равно длина strSource, нулевой символ не добавляется автоматически к скопированная строка. Если счет больше чем длина strSource, строка назначения дополняется нулем до количества символов.
str [0]
эквивалентно 0 [str]
, или, в более общем смысле, str [i]
равно ] i [str]
и i [str]
равно * (str + i)
.
Следующие функции могут использоваться для реализации неизменяемого strtok
:
strcspn(string, delimiters)
strspn(string, delimiters)
Первый находит первый символ в наборе переданных вами разделителей. второй находит первый символ , а не в наборе переданных вами разделителей.
Я предпочитаю их strpbrk
, поскольку они возвращают длину строки, если они не могут соответствовать .
Злоупотребление 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). Это не так очевидно для людей, у которых не было времени подумать об этом.
kmm уже имеет хороший список. Вот вещи, с которыми у меня были проблемы, когда я начал кодировать C.
Строковые литералы имеют собственный раздел памяти и всегда доступны. Следовательно, они могут быть, например, возвращаемым значением функции.
Управление памятью строк, в частности, с помощью библиотеки высокого уровня (не libc). Кто отвечает за освобождение строки, если она возвращается функцией или передается в функцию?
Когда следует использовать «const char *» и когда «char *». И что это говорит мне, если функция возвращает "const char *".
Все эти вопросы не так уж сложно выучить, но их трудно понять, если вы их не научите.