Функциональный формат в программе C

Используйте эти filter_var() функция, чтобы проверить, является ли строкой URL или нет:

var_dump(filter_var('example.com', FILTER_VALIDATE_URL));

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

РЕДАКТИРОВАНИЕ : Будьте осторожны, это решение не unicode-безопасно и не XSS-безопасно. При необходимости в сложной проверке возможно, лучше посмотреть где-то в другом месте.

6
задан Matthew Murdoch 17 August 2009 в 11:30
поделиться

10 ответов

Вариант 3 в значительной степени является негласным (?) Отраслевым стандартом. Если функция C на основе ввода-вывода, которая возвращает целое число, возвращает ненулевое целочисленное значение, это почти всегда означает, что операция ввода-вывода не удалась. Возможно, вы захотите обратиться к разделу этой Викибука о возвращаемых значениях в C / C ++.

Причина, по которой люди используют 0 для успеха, заключается в том, что существует только одно условие успеха. Затем, если он возвращает ненулевое значение, вы каким-то образом выясняете, что ненулевое значение означает с точки зрения ошибок. Возможно, 1 означает, что он не может выделить память, 2 означает, что аргумент недействителен, 3 означает, например, что произошла какая-то ошибка ввода-вывода. Технически, как правило, вы не вернете 1, но вернете XXX_ERR_COULD_NOT_MALLOC или что-то в этом роде.

Кроме того, never возвращают адреса локальных переменных . Если вы лично malloc не редактировали его, нет никаких гарантий относительно адреса этой переменной после возврата из функции. Прочтите ссылку для получения дополнительной информации.

6
ответ дан 9 December 2019 в 22:37
поделиться

В варианте 2 выше я бы вернулся адрес локальной переменной из my_function, но моя вызывающая функция будет использовать значение немедленно поэтому я считаю, что это нормально, и предполагаю место в памяти не было повторно используется (поправьте меня, если я неправильно).

Простите, но вы ошибаетесь, используйте метод Стива МакКоннелла или последний метод (кстати, в первом методе "int status" должно быть "int * status".

Вас простят за то, что вы думаете, что были бы правы, и это может сработать первые 99 999 раз, когда вы запустите программу, но 100000-й раз является ударом. В многопоточной или даже многопроцессорной архитектуре вы не можете полагайтесь, что кто-то или что-то не взял этот сегмент памяти и не использовал его, прежде чем вы дойдете до него.

Лучше перестраховаться, чем сожалеть.

2
ответ дан 9 December 2019 в 22:37
поделиться

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

также вариант 4,

char* my_function ( char *p_in_string, char* p_out_string )

, который для удобства просто возвращает p_out_string.

1
ответ дан 9 December 2019 в 22:37
поделиться

более безопасным способом было бы:

int my_function(const char* p_in_string, char* p_out_string, unsigned int max_out_length);

функция вернет статус, чтобы она была отмечена немедленно, как в

if( my_function(....) )

, и вызывающий будет выделять память для вывода, потому что

  1. вызывающий должен будет освободить ее, и это лучше всего сделать на том же уровне
  2. вызывающий будет знать, как он обрабатывает выделение памяти в целом , а не функцию
1
ответ дан 9 December 2019 в 22:37
поделиться
  1. void my_function (char * p_in_string, char * p_out_string, int * status)
  2. char * my_function (char * p_in_string, int * status)
  3. int my_function (char * p_in_string, char * p_out_string)

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

Вторая форма действительна только если my_function вызывает "malloc" или какой-то другой вариант выделения буфера. Это небезопасно в любой реализации c / c ++ для возврата указателей на локальные / стековые переменные. Конечно, когда my_function вызывает сам malloc, возникает вопрос, как освобождается выделенный буфер.

В некоторых случаях, вызывающий получает ответственность за освобождение буфера - вызывая free () , или, чтобы позволить различным уровням использовать разные распределители, через my_free_buffer (void *) , который вы публикуете . Еще один частый шаблон - вернуть указатель на статический буфер, поддерживаемый my_function - с условием, что вызывающий не должен ожидать, что буфер останется действительным после следующего вызова my_function.

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

Я наиболее предпочитаю форму

int my_function (char const * pInput, char * pOutput, int cchOutput) ;

Возвращает 0 в случае ошибки, или количество символов, скопированных в pOutput в случае успеха, при этом cchOutput является размером pOutput, чтобы предотвратить переполнение my_function буфера pOutput. Если pOutput равен NULL, то он возвращает точное количество символов, которое pOutput требует . Включая, конечно, место для нулевого терминатора.

// This is one easy way to call my_function if you know the output is <1024 characters
char szFixed[1024];
int cch1 = my_function(pInput,szFixed,sizeof(szFixed)/sizeof(char));

// Otherwise you can call it like this in two passes to find out how much to alloc
int cch2 = my_function(pInput,NULL,0);
char* pBuf = malloc(cch2);
my_function(pInput,pBuf,cch2);
1
ответ дан 9 December 2019 в 22:37
поделиться

Я предпочитаю вариант 3. Это значит, что я могу выполнять проверку ошибок для встроенной функции, то есть в операторах if. Кроме того, это дает мне возможность добавить дополнительный параметр для длины строки, если это необходимо.

int my_function(char *p_in_string, char **p_out_string, int *p_out_string_len)
0
ответ дан 9 December 2019 в 22:37
поделиться

2-й стиль:

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

0
ответ дан 9 December 2019 в 22:37
поделиться

Относительно вашего варианта 2:
Если вы вернете указатель на локальную переменную, которая была выделена в стеке, поведение не определено.
Если вы вернете указатель на выделенный вами фрагмент памяти ( malloc , calloc , ...), это будет безопасно (но уродливо, поскольку вы можете забыть бесплатно () ).

Я голосую за вариант 3:
Это позволяет вам управлять памятью вне my_function (...) , а также вы можете вернуть некоторый код состояния.

0
ответ дан 9 December 2019 в 22:37
поделиться

Я бы сказал, что вариант 3 - лучший способ избежать проблем с управлением памятью. Вы также можете выполнить проверку ошибок, используя целое число состояния.

0
ответ дан 9 December 2019 в 22:37
поделиться

Также стоит подумать, если ваша функция критична по времени. В большинстве архитектур быстрее использовать возвращаемое значение, чем ссылочный указатель. У меня был случай, когда при использовании возвращаемого значения функции я мог избежать доступа к памяти во внутреннем цикле, но с помощью указателя параметра значение всегда записывалось в память (компилятор не знает, будет ли доступ к значению через другой указатель где-нибудь еще). С помощью некоторого компилятора вы даже можете применять атрибуты к возвращаемому значению, которые нельзя выразить в указателях. Например, с такой функцией, как strlen, некоторый компилятор знает, что между вызовами strlen, если указатель не был изменен, то же значение будет возвращено и, таким образом, избежать вызова функции. В Gnu-C вы можете присвоить возвращаемому значению атрибут pure или даже const , что невозможно с параметром ссылки.

0
ответ дан 9 December 2019 в 22:37
поделиться
Другие вопросы по тегам:

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