2014-11-03 6 views
2

Я хочу прочитать список номеров, разделенных пробелами, хранящихся в строке.
Я знаю, как это может быть сделано с помощью stringstream в C++ -:Прочитать список чисел из строки

string s = "10 22 45 67 89"; 
stringstream ss(s); 
int numbers[100]; 
int k=0, next_number; 
while(ss>>next_number) 
    numbers[k++]=next_number; 

Мой вопрос заключается в том, как мы можем сделать это в C? Я читал о sscanf() в C, но я не уверен, что он может быть полезен здесь.

+1

Вы пытались использовать sscanf() в строке? Это довольно просто. – Fred

ответ

4

Вы можете использовать sscanf здесь, если вы знаете количество элементов вы ожидаете в строке:

char const *s = "10 22 45 67 89"; 

sscanf(s, "%d %d %d %d %d", numbers, numbers+1, numbers+2, numbers+3 numbers+4); 

Если, однако, вы не знаете, количество элементов априорных, вы можете попробовать выполнить токенизацию ввода, а затем попытаться преобразовать каждый элемент отдельно.

char s[] = "10 22 45 67 89"; 

char *n = strtok(s, " "); 
do { 
    numbers[k++] = atoi(n); 
} while (n = strtok(NULL, " ")); 

Обратите внимание, что strtok имеет довольно некрасивый интерфейс - он изменяет строку вы передаете его, и требует, чтобы вы использовать его примерно как указано выше - вы передаете строку ввода в первом вызове, а затем передать NULL для строки tokenize для последующих вызовов, пока вы не достигнете конца строки. Он хранит указатель на текущее местоположение внутри строки, что также создает проблему безопасности потоков.

Вы также можете использовать sscanf с %n преобразования для подсчета количества символов уже конвертирован, но это (ИМО) в почти прямой конкуренции с strtok для некоторых из самых уродливых кода мыслимого, и я не могу справиться разместить две вещи как в один день.

4

Используйте sscanf() и "%n, чтобы узнать, где начать следующее сканирование.

char *s = "10 22 45 67 89"; 
for (k=0; k<100; k++) { 
    int n; 
    int cnt = sscanf(s, "%d %n", numbers[k], &n); 
    if (cnt != 1) break; 
    s += n; 
} 
if (*s) Handle_DidNotEndCleanly(); 
0

Если порядок номеров не имеет значения, вы можете прокручивать строку назад, по одному символу за раз.

char s[] = "10 22 45 67 89"; 
int i; 
int tmp=0; 
int mult=1; 
for(i=strlen(s)-1; i>=0; i--) { 
    if(s[i] != ' ') { 
     tmp += (s[i]-'0') * mult; 
     mult *= 10; 
    } else { 
     // your number is stored in tmp, do whatever you want with it 
     tmp=0; 
     mult=1; 
    } 
} 

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

Этот метод не требует предварительного указания количества элементов в строке.

0
#include <stdio.h> 
#include <stdlib.h> 
#include <stdbool.h> 
#include <ctype.h> 

typedef struct ss {//Simple stringstream mock 
    const char *p; 
} Ss; 

Ss *ss_new(const char *s){ 
    Ss *ssp = malloc(sizeof(*ssp)); 
    ssp->p = s; 
    return ssp; 
} 

bool ss_nextInt(Ss *ssp, int *v){ 
    char *endp; 
    while(isspace(*ssp->p)) 
     ssp->p++; 
    if(!*ssp->p) 
     return false; 
    *v = strtol(ssp->p, &endp, 10); 
    if(ssp->p != endp){ 
     ssp->p = endp; 
     return true; 
    } 
    return false; 
} 
int main(){ 
    const char *s = "10 22 45 67 89"; 
    int numbers[100]; 
    int i, k=0, next_number; 
    Ss *ssp = ss_new(s); 
    while(ss_nextInt(ssp, &next_number)) 
     numbers[k++]=next_number; 
    free(ssp); 
    for(i = 0; i < k; ++i) 
     printf("%d\n", numbers[i]); 
    return 0; 
} 
0

В <string.h> существует множество вариантов разделить строки. strchr, strspn и strpbrk, чтобы назвать несколько. Наряду с функцией C90 strtol для парсинга чисел, определенных в <stdlib.h>.

strpbrk и strtol

#include <stdlib.h> // strtol 
#include <string.h> // strpbrk 
... 
const char *s = "10 22 45 67 89"; 
char *p = s; 
int numbers[MAX_NUMBERS]; 
size_t i = 0; 
do { 
    p = strpbrk(p, "-"); 
    if (p == NULL) break; 
    char *ptr; 
    int n = (int)strtol(p, &ptr, 10); 
    if (p == ptr) break; // in case *p == '-' and p[1] is not a number 
    numbers[i++] = n; 
} while (i < MAX_NUMBERS); 

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

strtol принимает строку, указатель для заполнения и базу.Он возвращает long, проанализированный из первой строки, и заполняет указатель местоположением конца номера или исходным указателем строки, если номер не был прочитан.

Смежные вопросы