В вашем коде есть несколько проблем.Вы можете использовать такие инструменты, как 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-аккуратный.Первое сообщение:
/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));
на
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);
на
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)
Хорошее обучение!