Изменить массив символов, переданный функции, C

Я хотел бы объединить 2 строки внутри функции. Однако я хотел бы, чтобы функция также изменяла строку назначения (массив символов).

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

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

char *my_strcat(char *dest, const char * src) {
    char *tab = (char*) malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));
    if(NULL == tab)
        return NULL;
    strcpy(tab, dest);
    strcpy(tab, src);
    free(dest);
    dest = (char*)malloc(sizeof(char) * (strlen(tab)+1));
    strcpy(dest, tab);
    return tab; }

int main(int argc, char **argv) {
    char *dst = NULL, *src = NULL, *r = NULL;
    int i;
    src = malloc(sizeof(char) * 100);
    strcpy(src, "fifty");

    dst = malloc (sizeof (char *) * 100);
    strcpy(src, "four");

    r = my_strcat(dst, src);
    printf("%s\n", r);
    printf("%s\n", dst);

    free(r);
    free(dst);
    free(src);

    return 0; }

person yak    schedule 03.06.2019    source источник
comment
strcpy(tab, dest); strcpy(tab, src); конечно не так. Возможно strcpy(tab, src); --› strcat(tab, src);   -  person chux - Reinstate Monica    schedule 03.06.2019
comment
@xing: Но как? Вот это самая большая проблема. Я пробовал это, но все еще ошибка сегмента   -  person yak    schedule 03.06.2019


Ответы (2)


dst размещается в main. Чтобы изменить это распределение в функции, вы можете вернуть новый указатель или передать указатель другому указателю. Поскольку вы возвращаете другой указатель, вы должны передать указатель на указатель char **dest и внести несколько изменений в функцию, чтобы учесть это изменение.

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

char *my_strcat ( char **dest, const char * src) {
    char *tab = malloc ( sizeof ( char) * (strlen ( *dest) + strlen ( src) + 1));//dereference dest
    if ( NULL == tab)
        return NULL;
    strcpy ( tab, *dest);//dereference dst
    strcat ( tab, src);
    free ( *dest);//dereference dest
    *dest = malloc ( sizeof ( char) * ( strlen ( tab) + 1));//dereference dest
    strcpy ( *dest, tab);//dereference dest
    return tab;
}

int main(int argc, char **argv) {
    char *dst = NULL, *src = NULL, *r = NULL;
    src = malloc ( sizeof ( char) * 100);
    strcpy ( src, "fifty");

    dst = malloc ( sizeof ( char) * 100);
    strcpy ( dst, "four");

    r = my_strcat ( &dst, src);//use address of dst
    printf ( "%s\n", r);
    printf ( "%s\n", dst);

    free ( r);
    free ( dst);
    free ( src);

    return 0;
}
person xing    schedule 03.06.2019

В вашем коде есть несколько проблем. Вы можете использовать такие инструменты, как valgrind, clang-tidy вам в помощь.

Вот ваш код с номерами строк

 1  /* -*- compile-command: "gcc prog.c; ./a.out"; -*- */
 2  #include <stdio.h>
 3  #include <stdlib.h>
 4  #include <string.h>
 5  
 6  char *my_strcat(char *dest, const char *src)
 7  {
 8    char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));
 9    if (NULL == tab)
10      return NULL;
11    strcpy(tab, dest);
12    strcpy(tab, src);
13    free(dest);
14    dest = (char *)malloc(sizeof(char) * (strlen(tab) + 1));
15    strcpy(dest, tab);
16    return tab;
17  }
18  
19  int main(int argc, char **argv)
20  {
21    char *dst = NULL, *src = NULL, *r = NULL;
22    int i;
23    src = malloc(sizeof(char) * 100);
24    strcpy(src, "fifty");
25  
26    dst = malloc(sizeof(char *) * 100);
27    strcpy(src, "four");
28  
29    r = my_strcat(dst, src);
30    printf("%s\n", r);
31    printf("%s\n", dst);
32  
33    free(r);
34    free(dst);
35    free(src);
36  
37    return 0;
38  }

Давайте используем cland-tidy для выполнения статического анализа:

clang-tidy-7 prog.c --

печатает кучу сообщений:

8 warnings generated.
/home/picaud/Temp/prog.c:8:46: warning: 1st function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage]
  char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));
                                             ^
/home/picaud/Temp/prog.c:26:9: note: Storing uninitialized value
  dst = malloc(sizeof(char *) * 100);
        ^
/home/picaud/Temp/prog.c:29:7: note: Calling 'my_strcat'
  r = my_strcat(dst, src);
      ^
/home/picaud/Temp/prog.c:8:46: note: 1st function call argument is an uninitialized value
  char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));
                                             ^
/home/picaud/Temp/prog.c:8:53: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *';

так далее...

Первые строки объясняют, что dest не инициализирован, вы можете отследить его до:

26    dst = malloc(sizeof(char *) * 100);
27    strcpy(src, "four");

что, безусловно, является ошибкой и должно быть заменено на

26    dst = malloc(sizeof(char *) * 100);
27    strcpy(dst, "four");

Теперь вы можете перезапустить clang-tidy. Первое сообщение такое:

/home/picaud/Temp/prog.c:8:53: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *';
remove * [clang-diagnostic-int-conversion]
  char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));             
                                                    ^~~~~

Что сразу указывает на другую ошибку, замените:

8     char *tab = (char *)malloc(sizeof(char) * (strlen(*dest) + strlen(src) + 1));

by

8     char *tab = (char *)malloc(sizeof(char) * (strlen(dest) + strlen(src) + 1));

у вас также есть

/home/picaud/Temp/prog.c:26:9: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'char *' [clang-analyzer-unix.MallocSizeof]
  dst = malloc(sizeof(char *) * 100);
        ^

следовательно, вы должны заменить:

  dst = malloc(sizeof(char *) * 100);

by

  dst = malloc(sizeof(char) * 100);

повторный запуск clang-tidy по-прежнему показывает некоторые проблемы:

 /home/picaud/Temp/prog.c:27:3: note: Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119
/home/picaud/Temp/prog.c:31:3: warning: Use of memory after it is freed [clang-analyzer-unix.Malloc]
  printf("%s\n", dst);
  ^
/home/picaud/Temp/prog.c:26:9: note: Memory is allocated
  dst = malloc(sizeof(char) * 100);
        ^
/home/picaud/Temp/prog.c:29:7: note: Calling 'my_strcat'
  r = my_strcat(dst, src);
      ^
/home/picaud/Temp/prog.c:9:3: note: Taking false branch
  if (NULL == tab)
  ^
/home/picaud/Temp/prog.c:13:3: note: Memory is released
  free(dest);
  ^
/home/picaud/Temp/prog.c:29:7: note: Returning; memory was released via 1st parameter
  r = my_strcat(dst, src);
      ^
/home/picaud/Temp/prog.c:31:3: note: Use of memory after it is freed
  printf("%s\n", dst);

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

/* -*- compile-command: "gcc prog.c; ./a.out"; -*- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *my_strcat(char *dest, const char *src)
{
  char *tab = (char *)malloc(sizeof(char) * (strlen(dest) + strlen(src) + 1));
  if (NULL == tab)
    return NULL;
  strcpy(tab, dest);
  strcpy(tab+strlen(dest), src);
  return tab;
}

int main(int argc, char **argv)
{
  char *dst = NULL, *src = NULL, *r = NULL;
  int i;
  src = malloc(sizeof(char) * 100);
  strcpy(src, "fifty");

  dst = malloc(sizeof(char) * 100);
  strcpy(dst, "four");

  r = my_strcat(dst, src);
  printf("%s\n", r);
  printf("%s\n", dst);

  free(r);
  free(dst);
  free(src);

  return 0;
}

при запуске этот код печатает:

gcc prog.c; ./a.out
fourfifty
four

Вы можете использовать valgrind для проверки отсутствия утечек памяти:

valgrind ./a.out 
==4023== Memcheck, a memory error detector
==4023== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4023== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==4023== Command: ./a.out
==4023== 
fourfifty
four
==4023== 
==4023== HEAP SUMMARY:
==4023==     in use at exit: 0 bytes in 0 blocks
==4023==   total heap usage: 4 allocs, 4 frees, 1,234 bytes allocated
==4023== 
==4023== All heap blocks were freed -- no leaks are possible
==4023== 
==4023== For counts of detected and suppressed errors, rerun with: -v
==4023== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Хорошее обучение!

person Picaud Vincent    schedule 03.06.2019