#c
#c
Вопрос:
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
int getCharNum(int a) { return a / (8 * sizeof(char)); }
int getBitNum(int a) { return a % (8 * sizeof(char)); }
int fromCharNum(int a) { return a * 8 * sizeof(char); }
int get2DimI(int a) { return getCharNum(a) / 187500; }
int get2DimJ(int a) { return getCharNum(a) % 187500; }
void rle_compress(char *src, char *dst, int ls, int *ld) {
uint8_t t[129];
int i, j = 0, k = 0, keep;
char out[187500];
t[0] = src[j];
while (j < ls) {
t[1] = src[j];
if (t[0] != t[1]) {
i = 1;
if (j < ls)
do
t[ i] = src[ j];
while (j < ls amp;amp; i < 128 amp;amp; t[i] != t[i - 1]);
if ((keep = t[i] == t[i - 1]))
--i;
out[k ] = (char)i;
t[0] = t[i];
if (!keep)
continue;
}
i = 2;
do
t[1] = src[ j];
while ( i < 130 amp;amp; t[0] == t[1]);
out[k ] = i 125;
out[k ] = t[0];
t[0] = t[1];
}
ld = amp;k;
dst = out;
}
void rle_extract(char *src, char *dst, int ls) {
int i, j, l = 0, k = 0, max;
char out[187500];
j = 0;
while (k 2 < ls) {
i = src[k ]; //segfault
j = src[k ];
max = i (i < 128 ? 1 : -126);
while (max--)
out[l ] = j;
}
dst = out;
return 0;
}
int main(void) {
int32_t n = 0;
scanf("%d", amp;n);
int32_t a[n];
int32_t b[] = { -1, -1, -1 };
char **count;
count = (char**)malloc(1000 * sizeof(char*));
int count_l[] = { [999] = 0 };
for (int i = 0; i < 1000; i) {
count[i] = (char*)malloc(187500 * sizeof(char));
char *temp = NULL;
rle_compress(count[i], temp, 187500, amp;count_l[i]);
free(count[i]);
count[i] = temp;
}
for (int i = 0; i < n; i )
scanf("%d", amp;a[i]);
for (int i = 0; i < n; i ) {
char *src = count[get2DimI(a[i]) / 187500];
char dst[187500];
rle_extract(src, dst, count_l[i / 187500]);
dst[get2DimJ(a[i])] ^= 1 << (getBitNum(a[i]));
rle_compress(dst, count[get2DimI(a[i]) / 187500], 187500, amp;count_l[i]);
}
int32_t mv = 187500000 / (8 * sizeof(char));
int j = 0;
for (int i = 0; i < mv; i ) {
char *src = count[i / 187500];
char dst[187500];
rle_extract(src, dst, count_l[i / 187500]);
int32_t x = dst[i % 187500];
if (x == 0)
continue;
for (int k = 0; k < 8 * sizeof(char); k ) {
if ((x >> (k)) amp; 1) {
b[j ] = fromCharNum(i) k;
}
}
//free(dst);
}
int m1 = min(b[0], min(b[1], b[2])),
m3 = max(b[0], max(b[1], b[2])),
m2 = b[0] b[1] b[2] - m1 - m3;
printf("%d %d %d", m1, m2, m3);
for (int i = 0; i < 1000; i)
free(count[i]);
free(count);
return 0;
}
Как исправить этот код?
Я пытаюсь сжать массив байтов (который должен сильно сжиматься, как n
и должно быть <=1500000
, а числа от 0
до 1.5*10^9
), но код выдает мне ошибку segfault на всех тестовых входах, которые я пробовал. Без сжатия все работало как по маслу, но требовалось много памяти (а ограничения составляют 64 мбАйТ).
Комментарии:
1. Используйте отладчик. Он немедленно и точно сообщит вам, какая строка кода вызывает ошибку сегментации. Это минимальная информация, которую вы должны были уже собрать для себя и для Stack Overlow. Отладчик также можно использовать для пошагового выполнения кода и проверки его во время выполнения.
2. Кроме того, предлагаю вам применить хорошую практику кодирования, чтобы сделать код отлаживаемым (для вас и для других) — используйте комментарии, используйте значимые имена переменных (не одиночные буквы), используйте
#define
значения вместо магических чисел.3. Проблема, о которой упоминал chrqlie, повторяется.
dst/out
. Либо измените имя аргумента сdst
наout
[и удалите локальный буфер], либо сделайте:char *out = dst;
вместо этого. Похоже, что функции сжатия и распаковки имеют эту проблему. Вmain
, у вас естьchar dst[187500]
в стеке . Вmain
, вы могли бы добавитьstatic
[или сделатьmalloc
так, как вы прокомментировали]. Это просто для того, чтобы исключить возможность того, что ошибка сегментации вызвана переполнением стека. После того, как код заработает, вы можете отменить это, если захотите.4. @CraigEstey Не должна ли программа использовать тот же объем, что и перед сжатием, если отредактировано так ideone.com/lCFgw3 ? Также это не единственная проблема, поскольку она по-прежнему выдает segfault, но в соответствии с gdb в другой строке.
Ответ №1:
Код неясен, но есть некоторые серьезные проблемы:
void rle_extract(char *src, char *dst, int ls)
не принимает выходной буфер от вызывающего объекта и не возвращает указатель на него:dst = out;
просто обновляет значение аргумента, а не переменную вызывающего объекта, переданную в качестве аргумента. Кромеreturn 0;
того, изvoid
функции также неверно.- в любом случае,
rle_extract
не следует возвращать его локальныйout
буфер, потому что он определяется только во время выполнения функции и отбрасывается, как только функция возвращается.
Вы должны либо передать буфер в качестве аргумента, либо выделить его локально и вернуть указатель вызывающему.
Могут быть и другие проблемы, нет объяснения того, что должен делать код.
Комментарии:
1. Предполагается, что код выводит уникальные значения из входных данных, учитывая, что их всего 3, все остальные присутствуют дважды. Основная идея: i-й бит представляет i-е натуральное число (будут представлены только числа от 0 до 1.5 * 10 ^ 9), соответствующий бит инвертируется каждый раз, когда появляется число, поэтому ответ — все числа из 1 бита. И из-за ограничений на количество чисел (менее 1500000) и ограничений на память (64 мбАйТ) Я должен сжать массив байтов с помощью кодировки длины выполнения. Я попытался прокомментировать код ideone.com/lCFgw3 и исправляет указанную проблему, но все еще есть ошибка segfault (но в другом месте в соответствии с gdb).