Как избавиться от ошибки сегментации?

#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).