Возвращать строки из функций неожиданной длины? - PullRequest
2 голосов
/ 03 октября 2010

C всегда довольно неловко со строками, но обычно хорошо просто выделить массив символов размером 256 для вашей строки и быть с ним в курсе.

Однако, что если вы хотите, чтобы функция возвращала строку, и вы не знаете ее размера, поскольку вы будете объединять строки десятки или сотни раз? Очевидно, что-то вроде этого не будет работать:

char * my_function(int n, char *string){
    if (n < 20) {
        return string;
    }
    else {
        char *new_string = "abcdefghijklmnop";
        strcat(string, new_string);
        return my_function(n--, string);
    }
}

Так как же это обрабатывается в c?

Ответы [ 5 ]

4 голосов
/ 03 октября 2010

Самый простой способ сделать функцию, которая объединяет произвольное количество строк, это:

  1. Переберите все строки и сложите их strlen().
  2. malloc() для общей длины.
  3. Выполните всю конкатенацию в строке malloc 'd, а затем верните ее.
3 голосов
/ 03 октября 2010

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

В любом случае, общее решение заключается в том, чтобы использовать динамическое распределение везде и постоянно перераспределять. Однако это неэффективно, и лучшим подходом может быть изменение предположения о том, что вы хотите объединить строки вообще (намного меньше сотен раз) и вместо этого создать свои строки с snprintf в одной операции. Затем вы можете сначала вычислить требуемый размер, и у вас есть возможность выделить его или просто использовать буфер фиксированного размера, в котором выходные данные могут быть усечены.

1 голос
/ 03 октября 2010

Существует несколько распространенных способов обработки возвращаемых строк, в которых конечный размер неизвестен:

  • вы делаете так, чтобы вызывающая сторона отвечала за передачу буфера для результата, который будет большимдостаточно, чтобы держать результат.Если вы делаете это, вы должны требовать, чтобы вызывающая сторона также передавала размер буфера, чтобы вы могли вернуть ошибку, если результат будет слишком большим, вместо того, чтобы переполнить буфер (то есть, следуйте примеру snprintf() вместоиз sprintf() s).

  • вы можете динамически распределять память для результата и назначать вызывающую функцию за освобождение памяти

Пара (непроверенных) примеров для вас my_function():

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

/*
  create new string in a dynamically allocated buffer
 */
char * my_function1(int n, char *s1)
{
    static char const new_string[] = "abcdefghijklmnop";

    int sz = strlen(s1) + (n * strlen(new_string)) + 1;

    char* result = malloc(sz);

    if (result) {
        strcpy(result, s1);

        while (n--) {
            strcat(result, new_string);
        }
    }

    return result;
}


/*
  create new string in a caller provided buffer
 */
int my_function2(int n, char *s1, char* buf, int buf_size)
{
    static char const new_string[] = "abcdefghijklmnop";

    int sz = strlen(s1) + (n * strlen(new_string)) + 1;

    if (sz > buf_size) {
        return -1; /* error */
    }

    strcpy(buf, s1);

    while (n--) {
        strcat(buf, new_string);
    }

    return sz-1; /* characters in result */
}
0 голосов
/ 03 октября 2010

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

Я предполагаю, что вы можете безопасно изменить объявление / инициализацию переданного аргумента string в вызывающей функции следующим образом:

char * string = calloc( 0, sizeof(char) ); 

Замените 0 на тот размер, который изначально имеет строка, плюс 1 для завершающего NULL.

Измените свою функцию на:

 char * my_function(int n, char *string){
    if (n < 20) {
        return string;
    }
    else 
    {
        char *new_string = "abcdefghijklmnop";
        if( (temp = realloc(string, strlen(new_string)+ strlen(string) + 1)) == NULL )
        { 
          printf("Memory allocation error"); 
          exit(1); 
        }
        strcat(string, new_string);
        return my_function(n--, string);
    }
}
0 голосов
/ 03 октября 2010

Вы хотели бы использовать что-то вроде этого:

void my_function ( ..., char ** result )
{
    // decide how many bytes...

    // Allocate enough memory.
    (*result) = malloc(number_of_bytes);

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