Си: Крашится на операторе return! И GCC на Linux лучше?
Ричард Молотов

Короче говоря, я не понимаю...Это обрывок из программы для генерации рандомных чисел в диапазоне, который запросит пользователь. Использую компилятор gcc версии 4.8.1 на window XP, и он просто ужасен! При компиляции он своевольно может изменяет значение переменной(не знаю от чего это зависит), даже когда я эту переменную вообще не трогал, а писал другой код в этой программе. Тут он тоже решил так напакостить, +программа крашится на месте где управление передается от функции show_ALL() к choise и main(), то есть когда управление возвращается в main(). Подумал я, что ошибка в компиляторе, и установил Code::Blocks(подумав, что это компилятор). Как только понял, что облажался, я смог скомпилировать программу через gcc компилятор(этот же), но уже в Code::Blocks ...И в этом случае указатель GRN не изменялся против моей воли, но прога все еще крашилась на отрывке возврата управления в main()(после запуска всех соответствующих функций). Далее я установил Digital Marc D, и наверное часа 3 настраивал его для работы в Code::Blocks'е. Черт его знает как у меня это получилось, но программа скомпилировалась теперь уже в DMD ии...Значение указателя тут ошибочно не изменялось, но она все равно крашилась на отрывке возврата управления в main(). Но DMD больше запустить у меня не удалось... Code::Blocks при попытке скомпилировать прогу выводит следующее:
dmd.exe -o -m32 -IC:\dmd\src\phobos -c have_problem_random.c -ofobj\Release\have_problem_random.obj
Error: -o no longer supported, use -of or -od
И не компилирует...
Попытки скомпилировать прогу через DMD вручную не окончались успехом.Не нашел инфу о том, что нужно писать в консоли(вернее нашел,но она не работала)...
Не знаю, может эти ошибки связаны между собой, то есть кривой компилятор и краш на return'е. Есть инфа, что на Linux подобной дичи с gcc не будет, и вот думаю переходить или нет.
Код напичкал printf() 'ом ибо не мог найти где идет ошибка.
Короче говоря,нужна помощ
```

include <stdio.h>

include <stdlib.h>

include <string.h>

include <time.h>

include <ctype.h>

void choise( const unsigned char* Amount_P,const unsigned long long* from_P,const unsigned long long*
to_P,const char** Order_P,const char** separator_P,const char** el_repeats_P);

void show_ALL(void** GRN_P,const unsigned char* type_pers,const char** Order_P,const char** separator_P,
const unsigned char* Amount_P,void** GRN_P_save);
void Generate(void** GRN_P,unsigned char* type_pers,unsigned char* Amount_P,const unsigned long long*
from_P,const unsigned long long* to_P,const char* el_repeats_P,signed char* signal_P,
const char* separator_P);
static const unsigned char SIZE_C = 5;
static const unsigned char SIZE_AM_C = 6;
static const unsigned char SIZE_FM_C = 14;
static const unsigned char SIZE_TO_C = 14;
static const unsigned char SIZE_OR_C = 5;
static const unsigned char SIZE_SP_C = 5;
static const unsigned char SIZE_ER_C = 5;

define ORDER_ASC "Ascending"//по возрастанию

define ORDER_DES "Descending"//по убыванию

define ORDER_ACC "Accidentally"//случайно

define SEPARATOR_SP "Space"//пробел

define SEPARATOR_CO "Comma"//запятая

define SEPARATOR_CAS "Comma and space"//запятая и пробел

define SEPARATOR_SEM "Semicolon"//точка с запятой

define ELIMINATE_REPEATS_ON "Included"

define ELIMINATE_REPEATS_OFF "Not included"

void main (void)
{
unsigned char Amount = 10;
unsigned long long from = 0;//начало диапазона по умолчанию
unsigned long long to = 40000;//конец диапазона по умолчанию
char* Order = ORDER_ASC;//или sequence - порядок следования чисел в выводе
char* separator = SEPARATOR_SP;
char* el_repeats = ELIMINATE_REPEATS_ON;//удаляет второе повторяющееся число

while(1)
{
    choise(&Amount,&from,&to,&Order,&separator,&el_repeats);
    printf("1323\n");
    getchar();
}
printf("\nExit.");
return;

}

void choise(const unsigned char* Amount_P,const unsigned long long* from_P,const unsigned long long*
to_P,const char** Order_P,const char** separator_P,const char** el_repeats_P)
{
void* GRN = NULL;//посредническая переменная между созданием и показом сгенерированых значений
void* GRN_save = NULL;//посредническая переменная между созданием и показом сгенерированых значений
unsigned char type_pers = 2;
signed char signal_per = 0;

Generate(&GRN,&type_pers,Amount_P,from_P,to_P,*el_repeats_P,&signal_per,*separator_P);//генерирует значения

printf("*GRN(2): %d\n", GRN);
GRN_save = GRN;//компилятор gcc версии 4.8.1 своевольно изменял значение указателя GRN,потому тут эта строка
show_ALL(&GRN,&type_pers,Order_P,separator_P,Amount_P,&GRN_save);//показывает сгенерированые значения
printf("sdas\n");
return;

}

void show_ALL(void** GRN_P,const unsigned char* type_pers,const char** Order_P,const char** separator_P,
const unsigned char* Amount_P,void** GRN_P_save)
{
//цикл: подсчитывает колво цифр в значении и пытается вместить в ряд
//и колво этих цифр,и +2 символа для разделителя.Когда максимальное колво символов в ряду
//достигнуто и дальше значение не помещается - выход из внутреннего цикла и запуск следую-
//щего внутреннего цикла,который вывод все значения вместе с разделительными символами на
//экран в 1 ряд.Когда вывело это,второй внутренний цикл заканчивает свою работу и управле-
//ние передается внешнему циклу,который проверяет сколько значений вывелось в одну стр-
//оку и если значения для вывода еще остались - внешний цикл запустится опять.Максимально
//символов в одной строке - 20(включительно).

if(*type_pers == 2)//unsigned short
{
    unsigned short* top = NULL;
    unsigned short* bottom = NULL;
    unsigned short temp = 0;

    unsigned short iT;
    unsigned short iB;

    /*перетасовка оригинальных сгенерированых значений через указатели на них*/
    if(*Order_P == ORDER_ASC)//по возрастанию
        for(top = (unsigned short*)GRN_P,iT = 0; iT < *Amount_P; iT++)
            for(bottom = (top+iT) + 1,iB = 0; iB < (*Amount_P)-iT-1; iB++)
                if(top[iT] > bottom[iB])//значения в массиве меняются местами
                {
                    temp = top[iT];
                    top[iT] = bottom[iB];
                    bottom[iB] = temp;
                }
    else if(*Order_P == ORDER_DES)//по убыванию
        for(top = (unsigned short*)GRN_P,iT = 0; iT < *Amount_P; iT++)
            for(bottom = (top+iT) + 1,iB = 0; iB < (*Amount_P)-iT-1; iB++)
                if(top[iT] < bottom[iB])//значения в массиве меняются местами
                {
                    temp = top[iT];
                    top[iT] = bottom[iB];
                    bottom[iB] = temp;
                }
    else if(*Order_P == ORDER_ACC)//случайно
        ;

    /*подготовка разделителя к работе*/
    char separator_in_use [3] = {'\0'};//разделитель будет выводиться как строка

    if(*separator_P == SEPARATOR_SP)//пробел
    {
        separator_in_use[0] = ' ';
    }
    else if(*separator_P == SEPARATOR_CAS)//запятая и пробел
    {
        separator_in_use[0] = ',';
        separator_in_use[1] = ' ';
    }
    else if(*separator_P == SEPARATOR_CO)//запятая
    {
        separator_in_use[0] = ',';
    }
    else if(*separator_P == SEPARATOR_SEM)//точка с запятой
    {
        separator_in_use[0] = ';';
    }

    unsigned short i_g = 0;//индекс по которому считается вывод чисел на экран
    unsigned short i_s = 0;//индекс по которому считается проверка чисел на вместимость в одной строке
    unsigned char i_out;//сколько значений выведется в одной строке(зависит от значения переменной nums_in_1_str_already)
    unsigned char smb_in_1_str;//эта переменная используется для проверки того,сколько символов вместилось в одну строку
    unsigned char nums_in_number;//используется чтобы хранить в себе значение показывающее сколько цифр в числе
    unsigned char nums_in_1_str_already;//показывает сколько чисел необходимо вывести в одну строку
    float probel = 0;//хранит значение - сколько пробелов должно быть перед числами и после них
    _Bool NTP = 0;//если значение пробелов не целое - добавить 1 пробел после вывода чисел

    printf("********************************************************************************");
    /*по-строковый вывод энного колва значений поставленых в одной строке*/
    while(i_g < *Amount_P)//пока колво выведенных чисел меньше, чем запрошеное колво чисел для вывода
    {
        printf("i_g: %d\n", i_g);//показывает сколько чисел уже вывело
        printf("*GRN_P(3): %d\n", *GRN_P);//на этом месте компилятор gcc версии 4.8.1 против моей воли зименял значение указателя
        printf("*GRN_P_save(3): %d\n", *GRN_P_save);//потому пришлось создать дополнительный указатель,чей адрес он не изменял, тобишь этот указатель
        for(smb_in_1_str = 0,nums_in_1_str_already = 0; smb_in_1_str < 21 && i_s < *Amount_P;i_s++)
        {//MAX 20 символов с троке

            unsigned short mediator_number = *(((unsigned short*)*(GRN_P_save))+i_s);//берет значение(из массива созданого функцией malloc())для того чтобы раздробить его и узнать сколько в нем цифр
            nums_in_number = 0;
            printf("mediator_number: %d\n", mediator_number);

            while(mediator_number /= 10)//количество цифр в этом одном значении
                nums_in_number++;

            nums_in_number++;//воспроивзоводство одного утеряного оборота

            smb_in_1_str += nums_in_number + 2;//колво цифр в значении + 2 символа отступа
            nums_in_1_str_already++;
        }
        //верхний цикл проверит в выражении данные о предыдущих числах
        //если числа для вывода еще остались и строка не переполнена - возмется следующее число и данные о его длинне + 2 символа отступа
        //добавятся в переменные smb_in_1_str и nums_in_1_str_already,проверка же,помещается ли предыдущася
        //строка уже вместе с этим числом преизойдет после того,как 2 последних переменных изменились,то есть
        //если это число не помещается в дополнение к строке - переменные smb_in_1_str и nums_in_1_str_already
        //все равно сохранились включая её,соответственно чтобы избежать ошибки, необходимы 2 оператора if ниже
        printf("smb_in_1_str(1): %d\n", smb_in_1_str);
        if(i_s != *Amount_P)//пока не является последним числом в массиве - истинно
        {
            i_s--;//снимает лишний набег
            //проверяло предыдущий,смотрело на следующий.Если проверка неуспешна-игнорировало
            //непоместившееся число и переходило на следующий.Тут идет защита от этого
            nums_in_1_str_already--;//снимает лишний набег
            smb_in_1_str -= nums_in_number + 2;//снимает лишний набег
        }
        else if(i_s == *Amount_P && !(smb_in_1_str < 21))//если 2 проверки в цикле дали нули
        {//(последнее число и переполнение строки) - ликвидировать переполнения строки
            i_s--;//снять лишние набеги
            nums_in_1_str_already--;
            smb_in_1_str -= nums_in_number + 2;
        }
        printf("smb_in_1_str(2): %d\n", smb_in_1_str);


        probel = (21-1) - smb_in_1_str;//строка с пробелами будет перед выводом чисел и после их вывода
        probel /= (float)2;

        if((float)probel != (int)probel)//если пробел нецелый - добавить 1 пробел в конце вывода значений
            NTP = 1;

        char mas_for_probel [(int)probel+1];//
        unsigned char i;
        for(i = 0; i < (int)probel; i++)
        {
            mas_for_probel[i] = ' ';
        }
        mas_for_probel[i] = '\0';

        printf("probel: %f\n",probel);

        if(*separator_P == SEPARATOR_SP && probel == 0)//все для красоты вывода ...
            printf("%30s", "|  ");
        else
            printf("%30s", "| ");

        printf("%s",mas_for_probel);//ставятся пробелы

        for(i_out = 0; i_out < nums_in_1_str_already; i_out++, i_g++)//выводятся значения
        {
            printf("%d%-2s",*(((unsigned short*)*(GRN_P_save))+i_g),separator_in_use);
        }
        //снимать последний набег i_g нельзя!он станет новой отправной точкой для следующего показа

        printf("%s",mas_for_probel);//ставятся пробелы
        if(NTP == 1)//если число пробелов было нецелым,то добавить пробел в конце
        {
            NTP = 0;
            printf(" ");
        }
        printf("%s\n", "|");
    }

    printf("********************************************************************************");
    free((unsigned short*)*GRN_P_save);//очищает массив рандомно сгенерированых значений

    printf("i_g);                   %d\n",i_g);                      
    printf("i_s);                   %d\n",i_s);                         
    printf("i_out);                 %d\n",i_out);                                                   
    printf("smb_in_1_str);          %d\n",smb_in_1_str);                    
    printf("nums_in_number);        %d\n",nums_in_number);            
    printf("nums_in_1_str_already); %d\n",nums_in_1_str_already);      
    printf("probel);                %f\n",probel);                        
    printf("NTP);                   %d\n",NTP);                          
    printf("GRN_P_save);            %d\n",GRN_P_save);                          
    printf("*GRN_P_save);           %d\n",*GRN_P_save);                          


    printf("Press <Enter> to continue...");

}
return;

}

void Generate(void** GRN_P,unsigned char* type_pers,unsigned char* Amount_P,const unsigned long long*
from_P,const unsigned long long* to_P,const char* el_repeats_P,signed char* signal_P,
const char* separator_P)
{
srand(time(NULL));//взятие начального значения
rand();//сход на 3 еденицы

if(*to_P <= 65535)
{
    unsigned char n_of_deleted_repeats = 0;//число удаленных повторений
    unsigned char ii_bef = 0;
    unsigned short mas_changders_dia [*Amount_P];//массив сгенерированых значений(всегда un_sh)
    for(unsigned char i = 0; i < *Amount_P; i++)//генерация и сохранение рандомных значений
    {
        mas_changders_dia[i] = rand();
    }

    for(unsigned char i = 0; i < *Amount_P; i++)//показ этих значений в выходном диапазоне функции rand() (от 0 до 32767)
    {
        printf("1mas_changders_dia[%d]: %d\n",i,mas_changders_dia[i]);
    }

    for(unsigned char i = 0; i < *Amount_P; i++)//перевод в необходимый диапазон сгенерированных чисел
        mas_changders_dia[i] = (((float)(*to_P - *from_P)/(float)(32767 - 0))**(mas_changders_dia + i)) + 
        *from_P;
    //берет количество чисел в диапазоне который запросил пользователь,делит это число на число диапазона чисел
    //в выходном диапазоне функции rand() и получается множитель,на размер диапазона пользователя относительно выходного диапазона
    //этот множитель применяется к переменным из массива mas_changders_dia и в итоге..График выходных значений сохраняет
    //резкие спады и подьемы выходных значений функции rand()

    if(el_repeats_P == ELIMINATE_REPEATS_ON)//исключить повторения
        for(unsigned char i = 0; i < *Amount_P; i++)//сравниваемое значение
            for(unsigned char ii = i+1; ii < *Amount_P; ii++)//сравнивается с остальными
                if(mas_changders_dia[i] == mas_changders_dia[ii])//если одинаковы
                {//удалить второе повторяющееся и сдвинуть все следующие числа к 0 индексу
                    n_of_deleted_repeats++;
                    ii_bef = ii;
                    for(unsigned char iii = ii+1; iii < *Amount_P; iii++, ii++)
                    {
                        mas_changders_dia[ii] = mas_changders_dia[iii];
                    }//доделать значения конца сдвинутого массива
                    if(ii > ii_bef)
                        ii = ii_bef-1;
                }

    for(unsigned char i = 0; i < *Amount_P; i++)//показывает значения уже переведненные в затребованый диапазон
    {
        printf("2mas_changders_dia[%d]: %d\n",i,mas_changders_dia[i]);
    }
    //снизу было else if
    if(el_repeats_P == ELIMINATE_REPEATS_OFF)//не исключать повторения 
        ;

    *GRN_P = malloc((*Amount_P -= n_of_deleted_repeats) * sizeof(unsigned short));
    //массив для вывода в пользоват. диапазоне

    printf("*GRN_P(1): %d\n", *GRN_P);

    for(unsigned char i = 0; i < *Amount_P; i++)//запись переведенных и отредактированых значений
        *(((unsigned short*)*(GRN_P))+i) = *(mas_changders_dia + i);//в готовый массив

    *type_pers = 2;
}
return;

}
```

Ричард Молотов около 1 года назадСпасибо 0
1 чел.