Модификация строк в C - PullRequest
1 голос
/ 06 сентября 2010

Мне нужно хранить следующие строки в 3-х переменных * переменные в C:

[foo]
[foo]:[bar]
[foo]:[bar]:[tat]

Каждая отдельная строка, такая как "foo", принимается в один момент времени через указатель char *, соответствующийВыходная строка генерируется непосредственно перед получением второй строки, и общее количество отдельных строк всегда известно.

Может быть произвольное количество строк.

Я написал следующий кодчтобы напечатать строки:

for(i=0;i<num;i++)
    {  
        for(j=0;j<=i;j++)
            {
                printf("[%s]",str[j]);
                if(j!=i)
                {
                    printf(":");
                }
                else
                {
                    printf("\n");
                }
            }       
    }   

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

Есть ли способ сделать это, который выглядит так же чисто, как простая печать строк?

Ответы [ 4 ]

3 голосов
/ 06 сентября 2010

Это утомительная проблема управления памятью и обработки строк в Си.Если я прав, думая, что для n входных строк вам нужно n выходных строк, каждая длиннее последней, я бы сделал это:

char **results = malloc(num * sizeof(char*));
if (results == 0) return ENOMEM;
int lastlen = 0;
for (int i = 0; i < num; ++i) {
    char *newresult = malloc(lastlen + strlen(str[i]) + 4);
    if (newresult == 0) { /* even more tedious freeing code goes here */ }
    results[i] = newresult;
    char *ptr = newresult;
    if (i != 0) {
        ptr += sprintf(ptr, "%s:", results[i-1])
    }
    sprintf(ptr, "[%s]", str[i])
    lastlen = strlen(newresult);
}

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

Правка: украл использование sprintf у Оскара.1009 * Другое редактирование: пример с asprintf, который доступен в GNU и BSD.Это включает в себя утомительный код освобождения, путь успеха на самом деле довольно хорош.Возвращает вновь выделенный массив при успехе, 0 при ошибке.Предполагается, что вызывающая сторона знает num и, следовательно, знает, как долго будет длиться массив: если это бесполезно, массив может заканчиваться нулем.

char **results = malloc(num * sizeof(char*));
if (results != 0) {
    const char *last = "";
    const char *sep = "";
    for (int i = 0; i < num; ++i) {
        if (asprintf(results + i, "%s%s[%s]", last, sep, str[i]) == -1) break;
        last = str[i];
        sep = ":";
    }
    if (i == num) return results; // success!
    // asprintf failed, so the value of results[i] is undefined
    while (i != 0) free(results[--i]);
    free(results); 
}
return 0;
1 голос
/ 07 сентября 2010

У вас есть две различные проблемы: , гарантирующие, что вы выделяете достаточно места , а также , создающие строку . Есть много способов сбалансировать их, но использование realloc() делает это довольно просто. Вот решение, которое проверяет и, при необходимости, увеличивает буфер.

Компромиссами в основном являются сложность кода и производительность, например:

  • Вычисление требований к памяти и выделение одного раза вместо более простого ( IMHO ) в цикле.
  • Потеря памяти из-за перерасхода по сравнению с потерей времени из-за (пере) распределения часто.
  • Использование более простого strcpy() по сравнению с более простым использованием с sprintf().

Моя версия

char *joinCmds( char* str[], /* The strings to concatenate */
                int num )    /* the number of strings */
{
    int  len = 0, i, off = 0;
    char *out = NULL, sep;

    for(i=0; i<num; i++)
    {
        while (len < (off+4+strlen(str[i]))) {
            len += 16384;      /* Larger numbers wastes memory in for better performance */
            out = realloc( out, len );  /* Warning: some 'realloc()' take 3 parameters */
            /** Handle NULL (Out of Memory errors) */
        }
        sep  = (i < (num-1)) ? ':' : '\n';
        off += sprintf(&out[off], "[%s]%c", str[i], sep);
    }
    return out;
}
1 голос
/ 06 сентября 2010

Вы можете использовать sprintf(). Используя ваш код в качестве примера:

for(i=0;i<num;i++)
{  
    char s[N];
    s[0] = '\0';
    for(j=0;j<=i;j++)
        {
            sprintf(s+strlen(s),"[%s]",str[j]);
            if(i!=j)
            {
                sprintf(s+strlen(s),":");
            }
            else
            {
                sprintf(s+strlen(s),"\n");
            }
        }      
    /* store 's' somewhere */
}   

Редактировать: Я бы не рекомендовал это решение для чего-то серьезного. Но для простого приложения, где вы просто хотите что-то сделать, оно должно делать свою работу. Просто достаточно N или выделите его динамически, чтобы можно было удерживать наибольшую строку.

0 голосов
/ 07 сентября 2010

раствор с strcpy; С sprintf это также просто.

char out[1000],*p=out; /* out with enough size */
int i=0;
/* num > 0 */
for(; i<num && (p+=strlen(strcpy(p,"]:["))) ; p+=strlen(strcpy(p,str[i++])) ) ;
strcpy(p,"]");
puts(out+2);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...