Из моего главного комментария: Вы выделяете new
в начале функции. Если какой-либо из операторов return
"раннего побега" будет выполнен, вы потеряете память.
Так нужно ли вводить free()
в каждый оператор return
? или как я могу исправить свой код?
Не делайте malloc
до после верхнего блока ранних побегов.
И, сделайте free
внизу. Для этого вам понадобится дополнительная переменная для хранения возвращаемого значения, чтобы вы могли безопасно выполнить free(new)
(например, double retval;
)
Примечание: Обычно чище заменить (например) *(new + i)
на new[i]
. Кроме того, поддержание кода в <= 80 символов / строка также является хорошим стилем. </p>
Вот один из способов исправить ваш код [прошу прощения за чистую стирку]:
double
findMedianSortedArrays(int *nums1, int nums1Size, int *nums2, int nums2Size)
{
int *new;
int i;
int count1 = 0;
int count2 = 0;
double retval;
if (nums1Size + nums2Size == 1) {
if (nums1Size == 1)
return *nums1;
else
return *nums2;
}
if (nums1Size == 0) {
if ((nums2Size & 0x1) == 0)
return (double) (nums2[nums2Size / 2 - 1] +
nums2[nums2Size / 2]) / 2;
else
return nums2[nums2Size / 2];
}
if (nums2Size == 0) {
if ((nums1Size & 0x1) == 0)
return (double) (nums1[nums1Size / 2 - 1] +
nums1[nums1Size / 2]) / 2;
else
return (double) nums1[nums1Size / 2];
}
// allocate this only when you're sure you'll use it
new = malloc(sizeof(int) * (nums1Size + nums2Size));
for (i = 0; i != (nums1Size + nums2Size); ++i) {
if ((nums1[count1 == nums1Size ? count1 - 1 : count1] >
nums2[count2 == nums2Size ? count2 - 1 : count2] &&
(count2) != nums2Size)
|| (count1) == nums1Size) {
new[i] = nums2[count2];
count2++;
}
else {
new[i] = nums1[count1];
count1++;
}
}
if (((nums1Size + nums2Size) & 0x1) == 0) {
retval = (double) (new[(nums1Size + nums2Size) / 2 - 1] +
new[(nums1Size + nums2Size) / 2]) / 2;
}
else
retval = (double) new[(nums1Size + nums2Size) / 2];
free(new);
return retval;
}
Но лично мне не нравятся множественные операторы return
в функции. Труднее отлаживать [используя gdb
], потому что вам нужно установить точку останова на каждый return
.
Вот версия, которая использует do { ... } while (0);
как "один раз" через «l oop», что позволяет нам исключить if/else
«лестничную» логику c [которую я также лично не люблю], и только single return
внизу. YMMV ...
double
findMedianSortedArrays(int *nums1, int nums1Size, int *nums2, int nums2Size)
{
int *new = NULL;
int i = 0;
int count1 = 0;
int count2 = 0;
double retval;
do {
if (nums1Size + nums2Size == 1) {
if (nums1Size == 1)
retval = *nums1;
else
retval = *nums2;
break;
}
if (nums1Size == 0) {
if ((nums2Size & 0x1) == 0)
retval = (double) (nums2[nums2Size / 2 - 1] +
nums2[nums2Size / 2]) / 2;
else
retval = nums2[nums2Size / 2];
break;
}
if (nums2Size == 0) {
if ((nums1Size & 0x1) == 0)
retval = (double) (nums1[nums1Size / 2 - 1] +
nums1[nums1Size / 2]) / 2;
else
retval = (double) nums1[nums1Size / 2];
break;
}
// allocate this only when you're sure you'll use it
new = malloc(sizeof(int) * (nums1Size + nums2Size));
for (; i != (nums1Size + nums2Size); ++i) {
if ((nums1[count1 == nums1Size ? count1 - 1 : count1] >
nums2[count2 == nums2Size ? count2 - 1 : count2] &&
(count2) != nums2Size)
|| (count1) == nums1Size) {
new[i] = nums2[count2];
count2++;
}
else {
new[i] = nums1[count1];
count1++;
}
}
if (((nums1Size + nums2Size) & 0x1) == 0) {
retval = (double) (new[(nums1Size + nums2Size) / 2 - 1] +
new[(nums1Size + nums2Size) / 2]) / 2;
}
else
retval = (double) new[(nums1Size + nums2Size) / 2];
} while (0);
if (new != NULL)
free(new);
return retval;
}
ОБНОВЛЕНИЕ:
спасибо! Я понял. ваш код более понятен, чем мой на самом деле !. но что вы думаете о производительности между ними? (if/else
и do{...}while(0))
. Потому что если мы предположим, что компилятор будет работать так, как мы обычно ожидаем, if/else
быстрее, чем если бы, который находится в do{...}
в пересмотренном коде. Большое спасибо!
На самом деле, если мы разберем обе версии [скомпилированные с -O2
], то версия do/while
будет на 4 инструкции по сборке короче.
Но, чтобы настроить ее, вы должны измерить ее .
Оптимизатор в значительной степени сделает их похожими.
Основная часть времени функции тратится на for
l oop, что одинаково для обоих. Скорость l oop превосходит любые дополнительные издержки do/while
, которые могут быть инструкцией ассемблера или двумя [но, опять же, do/while
имеет меньше инструкций].
Итак, настройка / оптимизация пролога / epilog-код функции [обычно] не стоит. Ускорение l oop - это.
Чтобы настроить / оптимизировать, либо выполните профилирование, чтобы определить, где код тратит наибольшее количество времени [ или для чего-то такого простого, это явно op], или добавьте метку времени и получите истекшее время для функции [или различных частей].
Как я уже упоминал, трудно добавить точку останова для функции, которая имеет несколько операторов return
.
Кроме того, иногда вы не можете подключить отладчик. Или трудно найти значимое место для установки точки останова. Например, если у вас есть программа, которая работает нормально (например, в течение нескольких дней), а затем прерывает работу после (например, в течение 63 часов), вам может потребоваться выполнить внутренний сравнительный анализ и отладку в стиле * 1084:
#ifdef DEBUG
#define dbgprint(_fmt) \
do { \
printf(_fmt); \
} while (0)
#else
#define dbgprint(_fmt) \
do { \
} while (0)
#endif
double
findMedianSortedArrays(int *nums1, int nums1Size, int *nums2, int nums2Size)
{
double retval;
dbgprint("findMedianSortedArrays: ENTER nums1Size=%d nums2Size=%d\n",
nums1Size,nums2Size);
// ... the code
dbgprint("findMediaSortedArrays: EXIT retval=%g\n",retval);
return retval;
}
Гораздо проще вставить операторы отладочной печати со второй версией.
Кстати, я все время так делаю. И одна из моих сильных сторон - быстрое улучшение кода и производительности [как я много пишу в реальном времени].