чтение строки, токенизация и присвоение struct в C - PullRequest
2 голосов
/ 21 декабря 2010

line это fgets'd и работает в цикле while со счетчиком n, d - это структура с двумя массивами символов, p и q. В основном, в нескольких словах, я хочу прочитать строку, разделить ее на 2 строки: одну до первого пробела, а другую - до конца строки. Я убираю потом (\n из файла становится \ '0'). Код работает, но есть ли более идиоматический способ сделать это? С какими ошибками я сталкиваюсь "по незнанию"?

    size_t spc = strcspn(line," ");
    strncpy(d[n].p, line, spc);
    d[n].p[spc+1]='\0';
    size_t l = strlen(line)-spc;
    strncpy(d[n].q, line+spc+1, l);
    char* nl = strchr(d[n].q, '\n');
    if(nl){
      *nl='\0';
    }
    n++;

РЕДАКТИРОВАТЬ : q может содержать пробелы.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 21 декабря 2010

Это может быть сделано только с чистой арифметикой указателя.Предполагая, что line содержит текущую строку:

char *p = line;
char *part1, *part2;

while (*p && *p != ' ') {
  p++;
}

if (*p == ' ') {
  *p++ = '\0';
  part1 = strdup(line);
  part2 = strdup(p);

  if (!part1 || !part2) {
    /* insufficient memory */
  }
} else {
  /* line doesn't contain a space */
}

В основном вы сканируете строку до первого появления пробела, а затем заменяете пробел нулевым символом, чтобы указать конец первой части (strdup необходимо знать, где остановиться) и переместить указатель на единицу, чтобы получить оставшуюся часть строки.

Чтобы код выглядел еще чище, но с дополнительными затратами на вызов функции вы могли бы использовать strchr() вместо цикла while:

char *p = strchr(line, ' ');
char *part1, *part2;

if (p) {
  *p++ = '\0';
  part1 = strdup(line);
  part2 = strdup(p);
}
1 голос
/ 21 декабря 2010

Я бы очень близко написал код, который у вас есть.Некоторые хитрости:

  • Вы не получаете ничего из strncpy здесь, используйте memcpy.
  • Вы не получаете ничего из strcspn, используйтеstrchr.
  • Избегайте сканирования частей строки дважды.

Итак:

char *spc = strchr(line, ' ');
memcpy(d[n].p, line, spc - line);
d[n].p[spc - line] = '\0';

spc++;
char *end = strchr(spc, '\n');
if (end)
{
    memcpy(d[n].q, spc, end - spc);
    d[n].q[end - spc] = '\0';
} 
else 
    strcpy(d[n].q, spc);

n++;
1 голос
/ 21 декабря 2010
scanf("%s %[^\n]", d[n].p, d[n].q);

Директива %[...] похожа на %s, но вместо сопоставления без пробелов она соответствует символам в скобках - или всем символам, кроме символов в скобках, если ^ является начальным.

Вы должны проверить возвращаемое значение, чтобы увидеть, действительно ли был введен q; это ведет себя несколько иначе, чем ваш код, если «остаток строки» на самом деле пуст. (Или если строка начинается с пробела.)

1 голос
/ 21 декабря 2010

Вы всегда можете использовать:

sscanf(line, "%s %s", d[n].p, d[n].q);

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

Функция scanf опасна, но очень полезна при правильном использовании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...