2014-01-09 4 views
4

У меня есть код этой add_str функции:языка C: конкатенация на строки указателя

void add_str(char *str1, char *str2, char **res) 
{ 
    int i; 
    int j = 0; 

    res[0] = malloc((strlen(str1) + strlen(str2) + 1) * sizeof(char)); 
    if (res[0] == NULL) 
    return; 
    for (i = 0; str1[i]; i++) 
    res[0][j++] = str1[i]; 
    for (i = 0; str2[i]; i++) 
    res[0][j++] = str2[i]; 
    res[0][j] = '\0'; 
} 

Он получает 2 строки, str1 и str2 и указатель строку **res, которая не является таНос. Моя функция добавляет str1 и str2 на ** res.

Мой вопрос: есть ли способ не писать res[0] каждый раз, когда мне нужно что-то с этим делать?

+1

'символьные * Темп = Рез [0];'? – user1781290

+1

Как насчет '* res'? –

+3

Кроме того, вы знаете о ['strcpy'] (http://en.cppreference.com/w/c/string/byte/strcpy) и [' strcat'] (http://en.cppreference.com/ ж/с/строки/байт/strcat)? –

ответ

6

res является указателем на указатель, так что вам нужно разыменования его, прежде чем использовать его. Вы правы, что res[0] - это неправильный способ сделать это, хотя в этом контексте. Вместо этого используйте (*res).

+1

Или вы можете просто передать 'char * res' вместо 'char ** res' ... И кроме того, вы можете использовать strcpy и strcat вместо двух циклов 'for'. –

+0

Ну, скобки нужны, если OP хочет продолжать использовать текущий код, так как '* res [j]' что-то отличается от '(* res) [j]'. –

+1

@barakmanos Затем OP не может выделить память в функции. –

3

То, что вы действительно хотите, чтобы разыменованием:

*res 
2

Зачем вам нужно передавать указатель указателя в любом случае? Вы могли бы точно так же изменить его к этому:

char *add_str(char *str1, char *str2) 
{ 
    char *res = malloc((strlen(str1) + strlen(str2) + 1)); 
    if (res == NULL) 
     return NULL; 

    char *ret = res; 

    while(*str1 != 0) 
     *res++ = *str1++; 

    while(*str2 != 0) 
     *res++ = *str2++; 

    *res = '\0'; 
    return ret; 
} 

Он имеет тот же эффект, и вы не должны иметь дело остроумия, что уродливая конструкция.

+0

Этот прототип был наложен, это школьное упражнение, которое я хотел оптимизировать. –

+0

Ах, я думал, что это может быть так. – Devolus

1

Это не является прямым ответом на ваш вопрос, но больше общих советов кодирования:

Для того, чтобы должным образом управлять всеми операциями динамической памяти в вашей программе, вы должны стремиться (попробуйте столько, сколько вы можете) иметь обе операции x=malloc(...) и free(x), выполненные из той же функции.

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

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

В таких случаях следует по-прежнему пытаться выполнять обе операции в рамках одной и той же «области» (класса, файла или модуля).

В вашем примере кодирования функция add_str выделяет буфер, но не освобождает его, что означает, что в конечном итоге ему понадобится другая функция (или у вас будут утечки памяти). Следовательно, если это возможно, тогда вы должны попытаться выполнить malloc вне этой функции.

+0

Это вздор. Весь смысл функции 'add_str' состоит в том, чтобы выделить новую строку, достаточно большую, чтобы удерживать две другие строки. Расчет требуемой памяти аккуратно завернут в функцию, где она необходима и скрыта от кода клиента. Ваш совет приведет к загромождению кода клиента такими вычислениями. Конечно, пользователю должно быть ясно, что ей нужно освободить память позже. Кроме того, можно утверждать, что функция будет проще использовать, если она вернет указатель вместо того, чтобы изменить его с помощью указателя на указатель. –

+0

@M Oehm: Прежде всего, ему не нужно «изменять указатель на указатель», поскольку он получит «обычный» указатель от пользователя и просто заполнит выделенный буфер данными. Во-вторых, именно так работают такие функции, как 'strcpy',' memcpy' и т. Д. - они НЕ выделяют новый буфер внутри, но вместо этого получают от пользователя буфер, который они считают достаточно большим для безопасного выполнения 'copy' операция. –

+0

Некоторые люди обычно смотрят только на текущую проблему, когда пытаются ее решить, игнорируя при этом другие проблемы, которые могут возникнуть в результате их решения. В приведенном выше коде код явно работает. Но в более широком масштабе у вас будет система с «malloc» и «free» s, разбросанная по коду. По моему опыту, вы быстро «теряете контроль» над своим управлением динамической памятью, и в итоге вы получаете несколько различных утечек памяти, о которых вы даже не подозреваете. –

0

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

void add_str(char *str1, char *str2, char **res) { 
    char* result = *res = malloc((strlen(str1) + strlen(str2) + 1) * sizeof(char)); 
    //Dereferencing a NULL pointer will safely crash your program on any sane system. 
    //if (!result) return; 
    int j = 0; //Since C99 you are allowed to mix code and variable declarations. 
    for(int i = 0; str1[i]; i++) result[j++] = str1[i]; 
    for(int i = 0; str2[i]; i++) result[j++] = str2[i]; 
    result[j] = '\0'; 
} 

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

void add_str(char *str1, char *str2, char **res) { 
    char* result = *res = malloc((strlen(str1) + strlen(str2) + 1) * sizeof(char)); 
    while(*str1) *result++ = *str1++; 
    while(*str2) *result++ = *str2++; 
    *result = '\0'; 
} 
Смежные вопросы