sscanf
не самый элегантный интерфейс, но он имеет много функций.Одним из них является возможность выяснить, где вы находитесь во входной строке, что позволяет извлекать (или просто указывать) «остальную часть ввода».
Например, после;
int nchar = -1;
int nfield = sscanf(line, "%u - %u - %u, %f , %f , %n", &year, &month,
&day, &temp, &uncertainty, &nchar);
nchar
будет содержать смещение в line
поля имени (если оно не равно -1, что указывает на то, что sscanf
не может соответствовать строке формата).Если это поле простирается до конца line
, вы можете использовать его напрямую (line + nchar
) или скопировать в другую строку после проверки, что оно не слишком длинное.
Если line
,вопреки его названию, содержит несколько строк, и вы хотите извлечь строку до символа новой строки, вы можете использовать два формата %n
с %*[^\n]
между ними (звездочка подавляет копию, чтобы избежать проблем с переполнением):
char name[NAME_MAX + 1];
int nstart = -1, nend = -1;
int nfield = sscanf(line, "%u - %u - %u, %f , %f , %n%*[^\n]%n", &year, &month,
&day, &temp, &uncertainty, &nstart, &nend);
if (nend > 0) {
if (nend - nstart <= NAME_MAX) {
memcpy(name, line + nstart, nend - nstart);
name[nend - nstart] = 0;
}
else {
/* name is too long */
}
}
else if (nstart > 0) {
/* Name was 0 bytes long. Sscanf requires that %[ match at least
* one character; if not, it fails the scan.
*/
name[0] = 0; /* Perhaps you wanted to signal an error
}
else {
/* Line didn't match format */
}
Очевидно, я мог бы избежать использования буфера фиксированной длины и необходимости проверять переполнение, динамически выделяя буфер, когда я знаю, насколько он велик:
char* name = NULL;
// ...
if (nend > 0)
name = strndup(line + nstart, nend - nstart);
// or, if you don't like strndup
// name = malloc(nend - nstart + 1);
// memcpy(name, line + nstart);
// name[nend - nstart] = 0;
Если вам действительно нужна динамически размещаемая строка, и у вас есть Posix-совместимый sscanf
, вы можете избежать этой проблемы, используя модификатор длины m
, который является универсальным простым решением.
char* name = NULL;
int nfield = sscanf(line, "%u - %u - %u, %f , %f , %m[^\n]", &year, &month,
&day, &temp, &uncertainty, &name);
Подробнее см. На странице sscanf
.Во всех случаях, когда name
выделяется динамически, не забывайте освобождать (), когда закончите.