Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Сделайте это как это:
char s[256];
strcpy(s, "one two three");
char* token = strtok(s, " ");
while (token) {
printf("token: %s\n", token);
token = strtok(NULL, " ");
}
Примечание: strtok
изменяет строку его маркирование, таким образом, это не может быть const char*
.
Вот пример использования strtok
, имейте в виду, что strtok
является деструктивным для его входной строки (и поэтому никогда нельзя использовать для строковой константы
char *p = strtok(str, " ");
while(p != NULL) {
printf("%s\n", p);
p = strtok(NULL, " ");
}
В основном следует отметить, что передача NULL
в качестве первого параметра в strtok
говорит ему получить следующий токен из строки, в которой он был ранее токенизирован.
strtok может быть очень опасным. Это не ориентировано на многопотоковое исполнение. Его надлежащее использование должно быть вызвано и в цикле, передающем в выводе от предыдущего вызова. Функция strtok имеет внутреннюю переменную, которая хранит состояние вызова strtok. Это состояние не уникально для каждого потока - это глобально. Если какой-либо другой код использует strtok в другом потоке, Вы получаете проблемы. Не вид проблем Вы хотите разыскать также!
я рекомендовал бы искать regex реализацию или использовать sscanf для разделения строки.
Попытка это:
char strprint[256];
char text[256];
strcpy(text, "My string to test");
while ( sscanf( text, "%s %s", strprint, text) > 0 ) {
printf("token: %s\n", strprint);
}
Примечание: 'текстовая' строка уничтожается, поскольку она разделяется. Это не может быть предпочтительным поведением =)
Можно упростить код путем представления дополнительной переменной.
#include <string.h>
#include <stdio.h>
int main()
{
char str[100], *s = str, *t = NULL;
strcpy(str, "a space delimited string");
while ((t = strtok(s, " ")) != NULL) {
s = NULL;
printf(":%s:\n", t);
}
return 0;
}
При чтении документации strtok я вижу, что вам нужно передать нулевой указатель после первого «инициализирующего» вызова. Может быть, вы этого не сделали. Просто предположение, конечно.
Вот еще одна реализация strtok()
, которая имеет возможность распознавать последовательные разделители (стандартная библиотека strtok()
не имеет этого)
Функция является частью библиотеки лицензированных строк BSD, называемой ] zString . Приглашаем вас принять участие:)
https://github.com/fnoyanisi/zString
char *zstring_strtok(char *str, const char *delim) {
static char *static_str=0; /* var to store last address */
int index=0, strlength=0; /* integers for indexes */
int found = 0; /* check if delim is found */
/* delimiter cannot be NULL
* if no more char left, return NULL as well
*/
if (delim==0 || (str == 0 && static_str == 0))
return 0;
if (str == 0)
str = static_str;
/* get length of string */
while(str[strlength])
strlength++;
/* find the first occurance of delim */
for (index=0;index<strlength;index++)
if (str[index]==delim[0]) {
found=1;
break;
}
/* if delim is not contained in str, return str */
if (!found) {
static_str = 0;
return str;
}
/* check for consecutive delimiters
*if first char is delim, return delim
*/
if (str[0]==delim[0]) {
static_str = (str + 1);
return (char *)delim;
}
/* terminate the string
* this assignmetn requires char[], so str has to
* be char[] rather than *char
*/
str[index] = '\0';
/* save the rest of the string */
if ((str + index + 1)!=0)
static_str = (str + index + 1);
else
static_str = 0;
return str;
}
Как упоминалось в предыдущих постах, с strtok()
, или тот, который я привел выше, полагается на переменную static *char
, чтобы сохранить местоположение последнего разделителя между последовательными вызовами, при работе с многопоточными приложениями следует соблюдать особую осторожность.