Используйте эти filter_var()
функция, чтобы проверить, является ли строкой URL или нет:
var_dump(filter_var('example.com', FILTER_VALIDATE_URL));
Это - плохая практика для использования регулярных выражений, если не необходимых.
РЕДАКТИРОВАНИЕ : Будьте осторожны, это решение не unicode-безопасно и не XSS-безопасно. При необходимости в сложной проверке возможно, лучше посмотреть где-то в другом месте.
Вариант 3 в значительной степени является негласным (?) Отраслевым стандартом. Если функция C на основе ввода-вывода, которая возвращает целое число, возвращает ненулевое целочисленное значение, это почти всегда означает, что операция ввода-вывода не удалась. Возможно, вы захотите обратиться к разделу этой Викибука о возвращаемых значениях в C / C ++.
Причина, по которой люди используют 0 для успеха, заключается в том, что существует только одно условие успеха. Затем, если он возвращает ненулевое значение, вы каким-то образом выясняете, что ненулевое значение означает с точки зрения ошибок. Возможно, 1 означает, что он не может выделить память, 2 означает, что аргумент недействителен, 3 означает, например, что произошла какая-то ошибка ввода-вывода. Технически, как правило, вы не вернете 1, но вернете XXX_ERR_COULD_NOT_MALLOC
или что-то в этом роде.
Кроме того, never возвращают адреса локальных переменных . Если вы лично malloc
не редактировали его, нет никаких гарантий относительно адреса этой переменной после возврата из функции. Прочтите ссылку для получения дополнительной информации.
В варианте 2 выше я бы вернулся адрес локальной переменной из my_function, но моя вызывающая функция будет использовать значение немедленно поэтому я считаю, что это нормально, и предполагаю место в памяти не было повторно используется (поправьте меня, если я неправильно).
Простите, но вы ошибаетесь, используйте метод Стива МакКоннелла или последний метод (кстати, в первом методе "int status" должно быть "int * status".
Вас простят за то, что вы думаете, что были бы правы, и это может сработать первые 99 999 раз, когда вы запустите программу, но 100000-й раз является ударом. В многопоточной или даже многопроцессорной архитектуре вы не можете полагайтесь, что кто-то или что-то не взял этот сегмент памяти и не использовал его, прежде чем вы дойдете до него.
Лучше перестраховаться, чем сожалеть.
Второй вариант проблематичен, потому что вам нужно получить память для строки результата, поэтому вы либо используете статический буфер (что, возможно, вызывает несколько проблем), либо выделяете память, что, в свою очередь, может легко вызвать утечку памяти, поскольку вызывающая функция несет ответственность за ее освобождение после использования, о чем легко забыть.
также вариант 4,
char* my_function ( char *p_in_string, char* p_out_string )
, который для удобства просто возвращает p_out_string.
более безопасным способом было бы:
int my_function(const char* p_in_string, char* p_out_string, unsigned int max_out_length);
функция вернет статус, чтобы она была отмечена немедленно, как в
if( my_function(....) )
, и вызывающий будет выделять память для вывода, потому что
void my_function (char * p_in_string, char * p_out_string, int * status)
char * my_function (char * p_in_string, int * status)
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);
Я предпочитаю вариант 3. Это значит, что я могу выполнять проверку ошибок для встроенной функции, то есть в операторах if. Кроме того, это дает мне возможность добавить дополнительный параметр для длины строки, если это необходимо.
int my_function(char *p_in_string, char **p_out_string, int *p_out_string_len)
2-й стиль:
Не думайте, что память не будет использоваться. Могут быть потоки, которые могут поглотить эту память, и у вас останется только нескончаемый мусор.
Относительно вашего варианта 2:
Если вы вернете указатель на локальную переменную, которая была выделена в стеке, поведение не определено.
Если вы вернете указатель на выделенный вами фрагмент памяти ( malloc
, calloc
, ...), это будет безопасно (но уродливо, поскольку вы можете забыть бесплатно ()
).
Я голосую за вариант 3:
Это позволяет вам управлять памятью вне my_function (...)
, а также вы можете вернуть некоторый код состояния.
Я бы сказал, что вариант 3 - лучший способ избежать проблем с управлением памятью. Вы также можете выполнить проверку ошибок, используя целое число состояния.
Также стоит подумать, если ваша функция критична по времени. В большинстве архитектур быстрее использовать возвращаемое значение, чем ссылочный указатель. У меня был случай, когда при использовании возвращаемого значения функции я мог избежать доступа к памяти во внутреннем цикле, но с помощью указателя параметра значение всегда записывалось в память (компилятор не знает, будет ли доступ к значению через другой указатель где-нибудь еще). С помощью некоторого компилятора вы даже можете применять атрибуты к возвращаемому значению, которые нельзя выразить в указателях. Например, с такой функцией, как strlen, некоторый компилятор знает, что между вызовами strlen, если указатель не был изменен, то же значение будет возвращено и, таким образом, избежать вызова функции. В Gnu-C вы можете присвоить возвращаемому значению атрибут pure или даже const , что невозможно с параметром ссылки.