malloc всему виной?
Интересный баг или фича от Borland C++.
#include <stdio.h> #include <string.h> #include <alloc.h> char *strinsn (char *s, char *t,int n) { int l1=strlen(s),l2=strlen(t); if (n<0 || n>l1) return NULL; char *p=(char *) calloc(l1+l2,sizeof(char)); return strcat(strcat(strncpy(p,s,n),t),&s[n]); } void main () { char *s1="abcdef", *s2="123"; int n=3; //may be from 0 to 6 inclusively for this test printf ("\n%s",strinsn (s1,s2,n)); }
Запускаем эту простую программку, содержащую единственную функцию
char *strinsn (char *s, char *t,int n)
Функция вставляет заданную указателем строку t
в строку s
, начиная с позиции n
.
Проверяется допустимость n
,
далее выделяется память под результирующую строку p
(оператор calloc
), первые n
символов
строки s
копируются в p
(вызов strncpy(p,s,n)
, который вернет указатель на p
),
затем к этому p
"прицепляется" строка t
(получается strcat(strncpy(p,s,n),t)
,
возвращён будет по-прежнему указатель на p
), наконец, к полученной строке дописывается "остаток"
исходной строки s
, начиная с символа под номером n
(напомню, что нумерация в Си ведется с нуля, так что он будет n+1
-м по порядку).
Внешний вызов strcat
также вернёт указатель на первый аргумент, поэтому
в результате всей функцией возвращается указатель именно на новую строку p
, под которую мы выделили память.
Всё это звучит верно и работает. Проблемы начинаются, когда мы выделяем память методом malloc
, а не calloc
.
Теоретически отличие только в том, что malloc
не "забивает" нулями выделяемую им память,
плюс размер памяти указывается в байтах единственным аргументом (у calloc
первым аргументом передаётся
число элементов, вторым - размер каждого элемента в байтах).
В общем, изменённая таким образом программка
#include <stdio.h> #include <string.h> #include <alloc.h> char *strinsn (char *s, char *t,int n) { int l1=strlen(s),l2=strlen(t); if (n<0 || n>l1) return NULL; char *p=(char *) malloc((l1+l2)*sizeof(char)); return strcat(strcat(strncpy(p,s,n),t),&s[n]); } void main () { char *s1="abcdef", *s2="123"; int n=3; //may be from 0 to 6 inclusively for this test printf ("\n%s",strinsn (s1,s2,n)); }
начинает вести себя странно. Вот выводы для 3 последовательных запусков.
abcDOWS\TEMP\scs22.tmp123def abcDOWS\TEMP\scs22.tmp123def123def abcDOWS\TEMP\scs22.tmp123def123def123def
Получиться, как понимаете, должно было во всех случаях
abc123def
Настройки компилятора и проч. были абсолютно одинаковы. Делать "по шагам", освобождать выделяемую память и прочее пробовал, ничего не помогло.
Кто бы объяснил в чём фича :)
Среда - учебная, Вorland C++ 3.1., но в своё время в ней писались вполне серьёзные проекты, в том числе и мной...
09.01.2010, 15:48 [9408 просмотров]