C - разделить / сохранить строку длины X в массив структур - PullRequest
1 голос
/ 12 ноября 2010

Я пытаюсь разбить строку на каждое количество символов X, а затем сохранить каждую строку в массиве структур.Тем не менее, мне интересно, что было бы кратким и эффективным способом сделать это.Я думал, что, возможно, я мог бы использовать sscanf, но не очень уверен, как это сделать.Любая помощь будет оценена.Пока у меня есть:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct st {char *str;};

int main ()
{
   struct st **mystruct;

   char tmp[] = "For configuration options (arch/xxx/config.in, and all the Config.in files),somewhat different indentation is used.";
   size_t max = 20, j = 0; // max length of string
   size_t alloc = strlen(tmp)/max + 1;

   mystruct = malloc(alloc * sizeof *mystruct);
   for (j = 0; j < alloc; j++)
      mystruct[j] = malloc(sizeof *mystruct[j]);

   const char *ptr = tmp;
   char field [ max ];
   int n;

   while (*ptr != '\0') {
        int line = sscanf(ptr, "%s", field, &n); // not sure how to use max in here
        mystruct[j]->str = field;
        field[0]='\0';
        if (line == 1)
            ptr += n;
        if ( n != max )
            break;
        ++ptr;
        ++j;
    }

   return 0;
}

Так что, когда я перебираю свою структуру, я могу получить что-то вроде:

For configuration op
tions (arch/xxx/conf
ig.in, and all the C
onfig.in files),some
what different inden
tation is used.

Ответы [ 5 ]

3 голосов
/ 12 ноября 2010

Вы можете использовать strncpy.

FYI:

char field [ max ];
while (...) {
    mystruct[j]->str = field;

Две проблемы с этим: (1) каждая структура в вашем массиве будет в конечном итоге указывать на одну и ту же строку, котораябудет иметь значение последней проверенной вами вещи, (2) они будут указывать на переменную в стеке, поэтому, когда эта функция вернется, они будут уничтожены.Это не проявляется здесь явно (например, ваша программа не взрывается), потому что функция оказывается «главной», но если вы переместили ее в отдельную подпрограмму и вызвали ее для разбора строки, вы получите обратно мусор.

mystruct не обязательно должно быть указателем на указатель.Для одномерного массива просто выделите блок N * sizeof *myarray для элементов N.

Распространенная идиома C при работе со структурами - это использование typedef, поэтому вам не нужно постоянно вводить struct foo,Например:

typedef struct { 
   int x, y;
} point;

Теперь вместо того, чтобы набирать struct point pt, вы можете просто сказать point pt.

1 голос
/ 12 ноября 2010

Если ваша строка не изменится после того, как вы ее разделите, я бы порекомендовал использовать такую ​​структуру:

struct st {
    char *begin;
    char *end;
};

или альтернативу:

struct st {
    char *s;
    size_t len;
};

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

0 голосов
/ 13 ноября 2010

Вы можете использовать (не стандарт C, но GNU) функцию strndup ().

#define _GNU_SOURCE
#include <string.h>

struct st {char *str;};

int main ()
{
   struct st *mystruct; /* i wonder if there's need for double indirection... */

   char tmp[] = "For configuration options (arch/xxx/config.in, and all the Config.in files),somewhat different indentation is used.";
   size_t max = 20, j = 0; // max length of string
   size_t alloc = (strlen(tmp) + max - 1)/max; /* correct round up */

   mystruct = malloc(alloc * sizeof mystruct);
   if(!mystruct) return 1; /* never forget testing if allocation failed! */

   for(j = 0; j<alloc; j++)
   {
      mystruct[j].str = strndup(tmp+alloc*max, max);
   }
}
0 голосов
/ 13 ноября 2010

Это достаточно просто?

#define SMAX 20
typedef struct {char str[SMAX+1];} ST;

int main()
{
  ST st[SMAX]={0};
  char *tmp = "For configuration options (arch/xxx/config.in, and all the Config.in files),somewhat different indentation is used.";
  int i=0,j;
  for( ; (st[i++]=*(ST*)tmp).str[SMAX]=0 , strlen(tmp)>=SMAX; tmp+=SMAX );

  for( j=0;j<i;++j )
    puts(st[j].str);

  return 0;
}
0 голосов
/ 12 ноября 2010

Один из вариантов - делать это посимвольно.

Рассчитать количество строк, которые вы делаете в данный момент.

Выделить память = (strlen (tmp) + number_of_lines) *sizeof (char)

Пройдитесь по входной строке, копируя символы из ввода во вновь выделенную память.Каждый 20-й символ вставьте нулевой байт, чтобы разделить эту строку.Сохраните указатель на начало каждой строки в вашем массиве структур.

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