с расщеплением символа * на символ ** - PullRequest
2 голосов
/ 27 ноября 2010

Я читаю строку из файла (char by char, используя fgetc ()), где все поля (имя, фамилия, ...) разделены ;.Теперь я хочу создать char**, добавить к нему все символы и заменить ; на \0, чтобы я фактически получил список всех полей.

Это действительно так?возможно?И когда я создаю символ **, например char ** buf = malloc(80), могу ли я рассматривать его как одномерный массив?Если память возвращена смежным malloc?

EDIT

Sry, предназначенный для замены ; на \0, бот \n.

РЕДАКТИРОВАТЬ 2

Этот код должен продемонстрировать, что я намерен делать (может немного уточнить):

int length = 80; // initial length char *buf = malloc(length); int num_chars = 0;

// handle malloc returning NULL

// suppose we already have a FILE pointer fp for (int ch = fgetc(fp); ch != EOF && ferror(fp) == 0; ch = fgetc(fp)) {
    if (length == size) { // expand array if necessary
        length += 80;
        buf = realloc(buf, length); 
        // handle realloc failure
    }

    if (ch == ';') {
        buf[num_chars] = '\0'; // replace delimiter by null-terminator
    } else {
        buf[num_chars] = ch; // else put char in buf
    } }

// resize the buffer to chars read buf
= realloc(buf, num_chars);

// now comes the part where I'm quite unsure if it works / is possible

char **list = (char **)buf; // and now I should be able to handle it like a list of strings?

Ответы [ 4 ]

2 голосов
/ 27 ноября 2010

Да, это возможно. Да, вы можете рассматривать это как одномерный массив. Да, память смежна.

Но вы, вероятно, хотите:

char ** fields = malloc(sizeof(char *) * numFields);

Тогда вы можете сделать:

// assuming `field` is a `char *`
fields[i++] = field;
1 голос
/ 27 ноября 2010

Возможно, что вспомогательный метод хочет, чтобы каждое из «полей» было записано в строку с нулевым символом в конце.Я не могу сказать.Вы можете сделать это с помощью strtok ().Однако strtok () имеет проблемы - он уничтожает исходную строку, «поданную» к нему.

#define SPLIT_ARRSZ 20   /* max possible number of fields */
char **
split( char *result[], char *w, const char *delim)
{
    int i=0;
    char *p=NULL;
    for(i=0, result[0]=NULL, p=strtok(w, delim); p!=NULL; p=strtok(NULL, delim), i++ )
    {
           result[i]=p;
           result[i+1]=NULL;
    }
    return result;
}

void
usage_for_split(void)
{
    char *result[SPLIT_ARRSZ]={NULL};
    char str[]="1;2;3;4;5;6;7;8;9;This is the last field\n";
    char *w=strdup(str);
    int i=0;
    split(result, w, ";\n");
    for(i=0; result[i]!=NULL; i++)
       printf("Field #%d = '%s'\n", i, result[i]);
    free(w);
}
1 голос
/ 27 ноября 2010

Это не совсем так, как вы описываете, но возможно нечто подобное.Более конкретно, последняя строка вашего примера char **list = (char **)buf; не будет делать то, во что вы верите.char **list означает, что элементы, на которые указывает * list, будут иметь тип char*, но содержимое *buf является символами.Следовательно, невозможно изменить одно на другое.

Вы должны понимать, что char ** - это просто указатель, он ничего не может содержать сам по себе.Но char ** может быть начальным адресом массива char *, каждый char * указывает на поле.

Вы должны будете выделить место для массива char *, используя первый malloc (или вы также можете использовать статический массив char * вместо char**. Вам также нужно будет найти место для каждого отдельного поля, возможно, выполнив malloc для каждого поля и скопировав его из исходного буфера. Если начальный буферпосле прочтения остается нетронутым, также можно использовать его для сохранения имен полей, но если вы просто замените начальный ; на \n, вы пропустите завершающий символ конца строки 0, вы не сможетезамените один символ на два символа.

Ниже приведен упрощенный пример того, что можно сделать (удаленная часть malloc, поскольку она мало добавляет к примеру и делает ее бесполезно сложной, это другая история):

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

main(){
    // let's define a buffer with space enough for 100 chars
    // no need to perform dynamic allocation for a small example like this
    char buf[100];
    const char * data = "one;two;three;four;";

    // now we want an array of pointer to fields, 
    // here again we use a static buffer for simplicity,
    // instead of a char** with a malloc
    char * fields[10];
    int nbfields = 0;
    int i = 0;
    char * start_of_field;

    // let's initialize buf with some data, 
    // a semi-colon terminated list of strings 
    strcpy(buf, data);

    start_of_field = buf;
    // seek end of each field and
    // copy addresses of field to fields (array of char*)
    for (i = 0; buf[i] != 0; i++){
        if (buf[i] == ';'){
            buf[i] = 0;
            fields[nbfields] = start_of_field;
            nbfields++;
            start_of_field = buf+i+1;
        }
    }

    // Now I can address fields individually
    printf("total number of fields = %d\n"
           "third field is = \"%s\"\n",
           nbfields, fields[2]);
}
1 голос
/ 27 ноября 2010

Теперь я хочу создать символ **, добавить к нему все символы

Вы должны выделить массив char (char *) для хранения символов, а не массив char * (char **).

И когда я создаю символ *, например char * buf = malloc (80) можно ли рассматривать это как одномерный массив? Если память возвращена malloc смежной?

Да, malloc всегда возвращает непрерывные блоки. Да, вы можете рассматривать его как одномерный массив char*80/sizeof char* элементами). Но вам нужно будет отдельно выделить память для каждой строки, хранящейся в этом массиве, или создать другой блок для хранения строковых данных, а затем использовать свой первый массив для хранения указателей на этот блок.

(или что-то еще; множество способов снять шкуру с этой кошки)

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