Ваша функция getmask()
вызывает неопределенное поведение:
- скопировать строковый аргумент в локальный массив
x
;
- вы разбираете это с помощью
strtok()
, который возвращает указатель в тот же локальный массив x
.
- Вы возвращаете этот указатель
mask
вызывающему. Этот указатель становится недействительным, как только вы выходите из этой функции.
Вы должны вместо этого вернуть указатель на выделенную копию этого массива, чтобы он оставался действительным после того, как вы вернетесь к вызывающему.
Более того, вы действительно должны избегать использования strtok()
, потому что он не реентерабелен: как вы заметили, вы не можете реализовать вложенные синтаксические анализаторы с помощью этой функции.
Другие функции доступны для разбора строк:
strchr()
находит символ в строке;
strstr()
находит подстроку в строке;
strspn()
соответствует набору символов в начале строки;
strcspn()
соответствует дополнению набора символов в начале строки;
- Вы также можете разобрать строку вручную, проверив символы в цикле.
Вот пример:
#include <stdlib.h>
#include <string.h>
char *getmask(const char *s) {
/* allocate a copy of the mask part
* the mask starts after the first '/'
* and stops at the first space or another '/'
*/
len - 0;
s = strchr(s, '/');
if (s != NULL) {
s++;
len = strcspn(s, "/ \t\r\n");
}
/* allocate space for the mask string */
char *mask = malloc(len + 1);
if (mask != NULL) {
/* copy the mask string */
memcpy(mask, s, len);
mask[len] = '\0';
}
return mask;
}
Функция является громоздким, но очень точным. Он ведет себя почти так же, как и то, что вы намеревались с strtok()
, единственное различие заключается в обработке нескольких последовательных байтов /
, которые strtok()
пропустили бы и strchr()
этого не сделает.
Вот альтернатива с sscanf()
:
#include <stdlib.h>
#include <string.h>
char *getmask(const char *s) {
char mask[256];
/* skip characters different from /, then skip slashes, then
* copy characters until another/or whitespace
*/
if (sscanf(s, "%*[^/]%*[/]%255[^/ \t\n]", mask) != 1) {
*mask = '\0';
}
return strdup(mask); /* POSIX function to allocate a copy of a string */
}
Это гораздо проще, но терпит неудачу, если строка начинается с /
.
strdup()
- очень полезная функция для размещения копии строки. Он доступен для POSIX-совместимых систем. Это вы не имеете его, он может быть легко реализована в виде:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *s) {
char *p = malloc(strlen(s));
if (p != NULL) {
strcpy(p, s);
}
return p;
}
Строки, выделенные getmask()
должны быть освобождены free()
, когда они больше не нужны.
Вы можете использовать похожие методы для синтаксического анализа входной строки в парах адресов ip/mask перед вызовом getmask()
.
Вы также могли бы обеспечить буфер назначения для getmask()
, чтобы избежать сложностей управления памятью:
char *getmask(char *dest, size_t size, const char *s) {
if (dest != NULL && size > 0) {
char mask[256];
/* skip characters different from /, then skip slashes, then
* copy characters until another/or whitespace
* dest cannot be used directly because size cannot be passed
* sscanf easily
*/
*dest = '\0';
if (sscanf(s, "%*[^/]%*[/]%255[^/ \t\n]", mask) != 1) {
strncat(dest, mask, size - 1);
}
}
return dest;
}
Синтаксический сложно, потому что вы должны быть осторожны, чтобы обрабатывать все случаи. Спецификации обычно недостаточно точны, поэтому разработчики должны делать выбор для особых случаев. Инструменты, предоставляемые библиотекой C для синтаксического анализа, являются старыми и неуклюжими, особенно strtok()
, sscanf()
. Будьте осторожны при использовании этих, даже опытные программисты укушены своими побочными эффектами и недостатками.
Вы начинаете с 'net = strtok (NULL," ")'? Описание проблемы запутанно. Показать минимальную программу с вводом и выводом. –
Извините, первый strtok до этого времени. Я отредактирую – Andrei
'strtok' работает как государственная машина, поэтому каждый вызов имеет состояние. Чтобы разделить серию маркеров, разделенных пробелами, и подмножество обозначений '/' с разделителями, вам нужно будет предотвратить столкновение состояний. Это можно сделать, повторяя дважды, или, как упоминалось в @Ludonope – Aaron3468