Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /************************************************************************************************************************\
- * *
- * *
- * Условие на курсов проект *
- * Да се състави и реализира алгоритъм за сливане на две сортирани последователности от масив *
- * на място (без използване на допълнителен масив). *
- * *
- * *
- \************************************************************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdbool.h>
- #ifdef _WIN32
- #include <windows.h>
- #include <psapi.h>
- /*
- Дефиниране на процедура, която служи
- за изкарването на информация колко памет е била заета от програмата в конзолата
- */
- static void printMemoryUsage(void)
- {
- PROCESS_MEMORY_COUNTERS memoryInfo;
- // Взимане на информация за паметта на текущия процес
- if (GetProcessMemoryInfo(GetCurrentProcess(), &memoryInfo, sizeof(memoryInfo)))
- {
- // WorkingSetSize е паметта (в байтове), която процесът използва във физическата RAM
- fprintf(stdout, "Memory used: %Lf MB\n", (long double)memoryInfo.WorkingSetSize / (1024.0L * 1024.0L));
- return;
- }
- fputs("\n\nCould not retrieve memory information.\n", stdout);
- }
- #endif
- #pragma warning(disable : 4996)
- #define bufferSize 20llu
- #define inputsText "Inputs:"
- #define expectedOutputsText "Expected outputs:"
- #define memoryAllocationFailedText "Memory allocation failed!"
- #define parsingWasNotSuccessfulText "Parsing wasn't successful!"
- #define delimiters "+-:;/\\, "
- #define redColouredText "\033[0;31m"
- #define greenColouredText "\033[0;32m"
- #define normalColouredText "\033[0m"
- #define checkIfPartOfNumber(currentLine, currentLineStart) \
- (isdigit(*(currentLine)) || \
- ((*(currentLine) == '-') && \
- isdigit(*((currentLine) + 1)) && \
- ((currentLine) == (currentLineStart) || \
- *((currentLine) - 1) == ' ')))
- /*
- Bitwise OR операцията с 32 превръща всяка главна буква ('A' до 'Z') в съответната малка буква,
- като добавя 32 към ASCII кода на символа. Това не засяга малките букви,
- защото те вече са в този диапазон. Така проверката дали символът е буква се свежда само до сравнение
- дали резултатът е между 'a' и 'z'.
- */
- #define checkIfLetter(currentCharacter) (((currentCharacter) | 32) >= 'a' && ((currentCharacter) | 32) <= 'z')
- #define checkIfDelimiter(delimitersByTheUser, currentCharacter) (strchr((delimitersByTheUser), (currentCharacter)) != NULL)
- // Деклариране на процедура без параметри, която служи за изпълнение на програмата
- void normalExecution(void);
- // Деклариране на процедура без параметри, която служи за тестване на програмата
- void testing(void);
- /*
- Деклариране на функция, която връща указател към променлива от тип char, с 1 параметър.
- - Указател към променлива от тип FILE
- Функцията служи за четене от конзолата или файл
- */
- char* readLine(FILE*);
- /*
- Деклариране на процедура със 7 параметъра.
- - Указател към променлива от тип FILE
- - Указател към указател към променлива от тип char
- - 2 yказателя към променливи от тип size_t
- - 2 yказателя към променливи от тип long
- - Променлива от тип bool
- Процедурата служи за намирането на броя редове и колко символа има най-дългият ред
- */
- void getLinesCountNumbersCountAndTheLongestNumberLength(FILE*, char**, size_t*, size_t*, long*, long*, bool);
- /*
- Деклариране на функция, която връща указател към указател към променлива от тип char, с 2 параметъра.
- - 2 променливи от тип size_t
- Функцията служи за заделяне на памет на двумерен char масив
- */
- char** allocateMemoryForTheInputsOrTheExpectedOutputsArray(size_t, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към указател към променлива от тип char
- - Променлива от тип size_t
- Процедурата служи за освобождаване на заделената памет от двумерен char масив
- */
- void freeTheMemoryFromTheArray(char**, size_t);
- /*
- Деклариране на процедура с 8 параметъра.
- - Указател към променлива от тип FILE
- - Указател към указател към променлива от тип char
- - Указател към променлива от тип char
- - Променлива от тип size_t
- - 3 променливи от тип long
- - Променлива от тип bool
- Процедурата служи за запълване на двумерен char масив с информация от конзолата или файл
- */
- void fillTheArrayWithTheInputsOrTheExpectedOutputsFromTheConsoleOrTheFile(FILE*, char**, char*, size_t, long, long, long, bool);
- /*
- Деклариране на процедура с 4 параметъра.
- - 2 указателя към константни променливи от тип char
- - Указател към указател към променлива от тип char
- - Променлива от тип size_t
- Процедурата служи за изкарване на двумерен char масив в конзолата
- */
- void printTheArray(const char*, const char*, char**, size_t);
- /*
- Деклариране на процедура с 5 параметъра.
- - 2 указателя към указатели към променливи от тип char
- - Указател към променлива от тип bool
- - Променлива от тип size_t
- - Променлива от тип bool
- Процедурата служи за обработка на всички редове на входния двумерен char масив
- */
- void processLines(char**, char**, bool*, size_t, bool);
- /*
- Деклариране на функция, която връща променлива от тип bool, с 5 параметъра.
- - Указател към указател към променлива от тип char
- - Указател към променлива от тип bool
- - Указател към указател към променлива от тип long long
- - 2 променливи от тип size_t
- Функцията служи за обработка на текущия ред на входния двумерен char масив
- */
- bool processLine(char**, bool*, long long**, size_t, size_t);
- /*
- Деклариране на функция, която връща променлива от тип size_t, с 1 параметър.
- - Указател към променлива от тип char
- Функцията служи за намиране на броя числа в текущия ред на входния двумерен char масив
- */
- size_t countNumbersInLine(char*);
- /*
- Деклариране на функция, която връща указател към променлива от тип long long, с 1 параметър.
- - Променлива от тип size_t
- Функцията служи за заделяне на памет на едномерен long long масив
- */
- long long* allocateMemoryForTheSequenceArray(size_t);
- /*
- Деклариране на функция, която връща променлива от тип bool, с 3 параметъра.
- - Указател към променлива от тип char
- - Указател към променлива от тип long long
- - Променлива от тип size_t
- Функцията служи за преобразуване на числата от текущия ред на входния двумерен char масив
- в тип long long и да се присвоят на едномерния long long масив
- */
- bool longLongTryParse(char*, long long*, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към променлива от тип long long
- - Променлива от тип size_t
- Процедурата служи за извикането на процедурата за намирането на края на първата поредица
- и при случай на намиране на край, извиква процедурата за пренареждането едномерния long long масив
- */
- void orderTheNumbersInTheSequenceAndCheckIfTheyAreCorrect(long long*, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към променлива от тип long long
- - Променлива от тип size_t
- Процедурата служи за изкарване на едномерен long long масив в конзолата
- */
- void printSequence(long long*, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към променлива от тип long long
- - Променлива от тип size_t
- Процедурата служи за намирането на края на първата поредица в едномерен long long масив
- */
- void orderSequence(long long*, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към променлива от тип long long
- - Променлива от тип size_t
- Процедурата служи за изместване на всеки елемент от едномерен long long масив с 1 индекс надясно
- */
- void shiftToTheRightWithOneIndex(long long*, size_t);
- /*
- Деклариране на процедура с 5 параметъра.
- - Указател към променлива от тип long long
- - Указател към указател към променлива от тип char
- - Указател към променлива от тип bool
- - 2 променливи от тип size_t
- Процедурата служи за сравнение на числата от едномерен long long масив с тези от изходния двимерен char масив,
- които се преoбразвуат в тип long long
- */
- void compareTheExpectedOutputsWithTheOutputsFromTheProgram(long long*, char**, bool*, size_t, size_t);
- /*
- Деклариране на процедура с 4 параметъра.
- - Указател към променлива от тип bool
- - Променлива от тип size_t
- - 2 указателя към константни променливи от тип char
- Процедурата служи за изкарването на резултатите от сравненията
- межди изходите от програмата и изходния двумерен char масив в конзолата
- */
- void printResults(bool*, size_t, const char*, const char*);
- /*
- Деклариране на функция, която връща указател към променлива от тип char, с 2 параметъра.
- - Указател към променлива от тип char
- - Променлива от тип size_t
- Функцията служи за повторно заделяне на памет на указател към променлива от тип char
- */
- char* reallocateMemoryForTheBuffer(char*, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към променлива от тип char
- - Променлива от тип size_t
- Процедурата служи за извикването на процедурите,
- които премахват ненужните whitespace символи преди и след низа,
- разделителите и се заменят с празно място
- */
- void trim(char*, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към променлива от тип char
- - Променлива от тип size_t
- Процедурата служи за премахването на ненужните whitespace символи преди и след низа
- */
- void trimLeadingAndTrailingWhitespaces(char*, size_t);
- /*
- Деклариране на процедура с 2 параметъра.
- - Указател към променлива от тип char
- - Променлива от тип size_t
- Процедурата служи за премахването на разделителите и се заменят с празно място
- */
- void removeDelimiters(char*, size_t);
- // Главна функция
- int main(void)
- {
- #ifdef _WIN32
- LARGE_INTEGER frequency; // Тикове в секунда
- // Взимане на честотата от брояча с голяма точност
- QueryPerformanceFrequency(&frequency);
- LARGE_INTEGER start; // Начален тик
- // Взимане на началния тик
- QueryPerformanceCounter(&start);
- //normalExecution();
- testing();
- // Изкарване на заетата памет от програмата в MB
- printMemoryUsage();
- LARGE_INTEGER end; // Краен тик
- // Взимане на крайния тик
- QueryPerformanceCounter(&end);
- // Изкарване на времето в конзолата, което е отнело за програмата, в милисекунди
- fprintf(stdout, "\nElapsed time: %Lf ms\n", (long double)((end.QuadPart - start.QuadPart) * 1000.0L / frequency.QuadPart));
- #endif
- return 0;
- }
- // Дефиниране на процедура, която служи за изпълнение на програмата
- void normalExecution(void)
- {
- size_t linesCount = 0;
- size_t longestLineLength = 0;
- char *bufferInput = NULL;
- fputs("Input a sequence: ", stdout);
- getLinesCountNumbersCountAndTheLongestNumberLength(stdin, &bufferInput, &linesCount, &longestLineLength, 0, 0, true);
- char **input = allocateMemoryForTheInputsOrTheExpectedOutputsArray(linesCount, longestLineLength);
- fillTheArrayWithTheInputsOrTheExpectedOutputsFromTheConsoleOrTheFile(stdin, input, bufferInput, linesCount, 0, 0, 0, true);
- fputs("\nInput the expected output: ", stdout);
- char *bufferOutput = readLine(stdin);
- char **expectedOutput = allocateMemoryForTheInputsOrTheExpectedOutputsArray(linesCount, longestLineLength + 28);
- fillTheArrayWithTheInputsOrTheExpectedOutputsFromTheConsoleOrTheFile(stdin, expectedOutput, bufferOutput, linesCount, 0, 0, 0, true);
- bool *resultsCheck = (bool*)malloc(linesCount * sizeof(bool));
- if (resultsCheck == NULL) return;
- memset(resultsCheck, true, linesCount * sizeof(bool));
- processLines(input, expectedOutput, resultsCheck, linesCount, true);
- freeTheMemoryFromTheArray(input, linesCount);
- freeTheMemoryFromTheArray(expectedOutput, linesCount);
- printResults(resultsCheck, linesCount, "\n\nChecking if the expected output matches the output from the program:\n", "Comparison");
- free(resultsCheck);
- }
- // Дефиниране на процедура, която служи за тестване на програмата
- void testing(void)
- {
- /*
- Деклариране на указател към променлива тип FILE, която позволя отварянето на файлове чрез функцията fopen().
- Функцията fopen(const char *filename, const char *mode) приема 2 низа за параметри.
- Единият съдържа директория на файл, а другият действието, което ще се изпълнява.
- Те биват за текстови файлове:
- "r": Отваряне за четене. Файлът трябва да същестува.
- "w": Отваряне за записване. Създава празен файл или директно записва върху същестуващ в дадената директория.
- "a": Отваряне за добавяне. Записва информация в края на файла. Създава файл, ако не съществува.
- "r+": Отваряне за четене и за записване. Файлът трябва да същестува.
- "w+": Отваряне за четене и за записване. Създава празен файл или директно записва върху същестуващ в дадената директория.
- "a+": Отваряне за четене и за добавяне. Създава файл, ако не съществува.
- и други.
- Файловете могат да бъдат текстови, binary, bitmap и т.н..
- Действията за binary файловете са същите като текстовите файлове,
- но само трябва да се добави буквата 'b' след последната написана буква.
- В този случай е текстови файл и ще се чете от него
- */
- FILE *tests = fopen("tests1.txt", "r");
- // Проверка дали същестува този файл
- if (tests == NULL)
- {
- fprintf(stdout, "Error: A file with this name can't be found at this directory:\n%s\n\n", "tests1.txt");
- return;
- }
- size_t linesCount = 0;
- size_t longestLineLength = 0;
- long inputsPosition = 0;
- long outputsPosition = 0;
- getLinesCountNumbersCountAndTheLongestNumberLength(tests, NULL, &linesCount, &longestLineLength, &inputsPosition, &outputsPosition, false);
- // Проверка дали файлът е празен
- if (linesCount == 0)
- {
- fputs("No tests were found in the file!\n", stdout);
- // Затваряне на файла
- fclose(tests);
- return;
- }
- // Деклариране на двумерен символен масив (низ) и заделяне на памет с броя редове и символи на най-дългия ред
- char **inputs = allocateMemoryForTheInputsOrTheExpectedOutputsArray(linesCount, longestLineLength + 1);
- fillTheArrayWithTheInputsOrTheExpectedOutputsFromTheConsoleOrTheFile(tests, inputs, "", linesCount, inputsPosition, outputsPosition, inputsPosition, false);
- // Деклариране на двумерен символен масив (низ) и заделяне на памет с броя редове и символи на най-дългия ред
- char **expectedOutputs = allocateMemoryForTheInputsOrTheExpectedOutputsArray(linesCount, longestLineLength + 28);
- fillTheArrayWithTheInputsOrTheExpectedOutputsFromTheConsoleOrTheFile(tests, expectedOutputs, "", linesCount, inputsPosition, outputsPosition, outputsPosition, false);
- // Затваряне на файла
- fclose(tests);
- /*
- Изкарване на съдържанието на масива в конзолата,
- за да се провери дали правилно е записано съдържанието взето от файла
- */
- printTheArray("Inputs:\n", "Test #", inputs, linesCount);
- /*
- Изкарване на съдържанието на масива в конзолата,
- за да се провери дали правилно е записано съдържанието взето от файла
- */
- printTheArray("\nExpected outputs:\n", "Expected output #", expectedOutputs, linesCount);
- bool *resultsCheck = (bool*)malloc(linesCount * sizeof(bool));
- if (resultsCheck == NULL) return;
- memset(resultsCheck, true, linesCount * sizeof(bool));
- processLines(inputs, expectedOutputs, resultsCheck, linesCount, false);
- freeTheMemoryFromTheArray(inputs, linesCount);
- freeTheMemoryFromTheArray(expectedOutputs, linesCount);
- printResults(resultsCheck, linesCount, "\n\nChecking if the expected outputs match the outputs from the program:\n", "Test");
- free(resultsCheck);
- }
- // Дефиниране на функция, която служи за четене от конзолата или файл
- char* readLine(FILE *inputSource)
- {
- size_t currentBufferSize = bufferSize;
- char *buffer = (char*)malloc(currentBufferSize * sizeof(char));
- if (buffer == NULL) return NULL;
- size_t currentLength = 0;
- int currentCharacterAsItsASCIIValue = 0;
- while ( ((currentCharacterAsItsASCIIValue = fgetc(inputSource)) != '\n') && (currentCharacterAsItsASCIIValue != EOF) )
- {
- buffer[currentLength++] = (char)currentCharacterAsItsASCIIValue;
- if (currentLength >= currentBufferSize)
- {
- currentBufferSize *= 2;
- if ( (buffer = reallocateMemoryForTheBuffer(buffer, currentBufferSize)) == NULL ) return NULL;
- }
- }
- buffer[currentLength] = '\0';
- if ( (currentLength == 0) && (currentCharacterAsItsASCIIValue == EOF) )
- {
- free(buffer);
- return NULL;
- }
- if (!checkIfLetter(buffer[0])) trim(buffer, currentLength);
- currentLength = strlen(buffer);
- if ( (currentLength + 1) < currentBufferSize ) // +1 за '\0'
- {
- if ( (buffer = reallocateMemoryForTheBuffer(buffer, currentLength + 1)) == NULL ) return NULL;
- }
- return buffer;
- }
- /*
- Дефиниране на процедура, която служи за намирането
- на броя редове и колко символа има най-дългият ред
- */
- void getLinesCountNumbersCountAndTheLongestNumberLength(FILE *tests, char **result, size_t *linesCount, size_t *longestLineLength, long *inputsPosition, long *outputsPosition, bool isOneLine)
- {
- char *buffer = NULL;
- size_t currentLineLength = 0;
- while ( (buffer = readLine(tests)) != NULL )
- {
- if ( !isOneLine && !strcmp(buffer, inputsText) )
- {
- free(buffer);
- *inputsPosition = ftell(tests); // Взимане на позицията, на която стоят входовете от файла
- continue;
- }
- else if ( !isOneLine && !strcmp(buffer, expectedOutputsText) )
- {
- free(buffer);
- *outputsPosition = ftell(tests); // Взимане на позицията, на която стоят очакваните изходи от файла
- break;
- }
- (*linesCount)++;
- currentLineLength = strlen(buffer);
- if (currentLineLength > *longestLineLength)
- {
- *longestLineLength = currentLineLength;
- }
- if (isOneLine)
- {
- *result = (char*)malloc((currentLineLength + 1) * sizeof(char));
- strcpy(*result, buffer);
- break;
- }
- free(buffer);
- }
- }
- // Дефиниране на функция, която служи за заделяне на памет на двумерен char масив
- char** allocateMemoryForTheInputsOrTheExpectedOutputsArray(size_t linesCount, size_t longestLineLength)
- {
- char **result = (char**)malloc(linesCount * sizeof(char**));
- if (result == NULL) return NULL;
- for (size_t i = 0; i < linesCount; i++)
- {
- result[i] = (char*)malloc(longestLineLength * sizeof(char*));
- if (result[i] == NULL)
- {
- for (size_t j = 0; j < i; j++)
- {
- free(result[j]);
- }
- free(result);
- return NULL;
- }
- }
- return result;
- }
- /*
- Дефиниране на процедура, която служи
- за освобождаване на заделената памет от двумерен char масив
- */
- void freeTheMemoryFromTheArray(char **result, size_t linesCount)
- {
- for (size_t i = 0; i < linesCount; i++)
- {
- free(result[i]);
- }
- free(result);
- }
- /*
- Дефиниране на процедура, която служи
- за запълване на двумерен char масив с информация от конзолата или файл
- */
- void fillTheArrayWithTheInputsOrTheExpectedOutputsFromTheConsoleOrTheFile(FILE *tests, char **results, char *output, size_t linesCount, long inputsLocation, long outputsLocation, long startingReadingPosition, bool isOneLine)
- {
- char *buffer = isOneLine ? output : NULL;
- if (!isOneLine)
- {
- fseek(tests, startingReadingPosition, SEEK_SET);
- }
- for (size_t i = 0; i < linesCount; i++)
- {
- if ( !isOneLine && ((buffer = readLine(tests)) == NULL) )
- {
- fprintf(stdout, "Error: Test #%zu can't be read!\n\n", i + 1);
- continue;
- }
- /*
- Прекратяване на записването, ако има повече от един вход, позицията,
- откоято е зададен pointer-ът да се движи, е еднаква с тази на позицията
- на входовете и полученият текст в низа с име buffer е "Expected outputs:"
- */
- if ( !isOneLine && (startingReadingPosition == inputsLocation) && !strcmp(buffer, expectedOutputsText) )
- {
- free(buffer);
- break;
- }
- strcpy(results[i], buffer);
- results[i][strlen(buffer)] = '\0';
- free(buffer);
- if (isOneLine) break;
- }
- }
- /*
- Дефиниране на процедура, която служи
- за изкарване на двумерен char масив в конзолата
- */
- void printTheArray(const char *prompt, const char *promptTwo, char **results, size_t linesCount)
- {
- fputs(prompt, stdout);
- for (size_t i = 0; i < linesCount; i++)
- {
- fprintf(stdout, "%s%02zu: %s\n", promptTwo, i + 1, results[i]);
- }
- }
- /*
- Дефиниране на процедура, която служи
- за обработка на всички редове на входния двумерен char масив
- */
- void processLines(char **inputs, char **expectedOutputs, bool *resultsCheck, size_t linesCount, bool isOneLine)
- {
- long long *sequence = NULL;
- size_t currentLineNumbersCount = 0;
- for (size_t i = 0; i < linesCount; i++)
- {
- if (!isOneLine)
- {
- fprintf(stdout, "\n\nTest #%02zu:\n", i + 1);
- }
- currentLineNumbersCount = countNumbersInLine(inputs[i]);
- if (!processLine(inputs, resultsCheck, &sequence, i, currentLineNumbersCount)) continue;
- orderTheNumbersInTheSequenceAndCheckIfTheyAreCorrect(sequence, currentLineNumbersCount);
- compareTheExpectedOutputsWithTheOutputsFromTheProgram(sequence, expectedOutputs, resultsCheck, i, currentLineNumbersCount);
- free(sequence);
- if (isOneLine) break;
- }
- }
- /*
- Дефиниране на функция, която служи
- за обработка на текущия ред на входния двумерен char масив
- */
- bool processLine(char **inputs, bool *resultsCheck, long long **sequence, size_t currentLineIndex, size_t currentLineNumbersCount)
- {
- if ( (*sequence = allocateMemoryForTheSequenceArray(currentLineNumbersCount)) == NULL )
- {
- fprintf(stdout, "\nError: Memory allocation failed for Test #%zu!\nSkipping the invalid test and continuing to the next one!\n", currentLineIndex + 1);
- resultsCheck[currentLineIndex] = false;
- return false;
- }
- if (!longLongTryParse(inputs[currentLineIndex], *sequence, currentLineNumbersCount))
- {
- free(*sequence);
- fprintf(stdout, "\nError: Parsing wasn't successful for Test #%zu!\nSkipping the invalid test and continuing to the next one!\n", currentLineIndex + 1);
- resultsCheck[currentLineIndex] = false;
- return false;
- }
- return true;
- }
- /*
- Дефиниране на функция, която служи
- за намиране на броя числа в текущия ред на входния двумерен char масив
- */
- size_t countNumbersInLine(char *currentLine)
- {
- size_t currentLineNumbersCount = 1; // + 1, за да може и последното число да бъде преброено
- while (*currentLine)
- {
- if (*currentLine++ == ' ') currentLineNumbersCount++;
- }
- return currentLineNumbersCount;
- }
- /*
- Дефиниране на функция, която служи
- за заделяне на памет на едномерен long long масив
- */
- long long* allocateMemoryForTheSequenceArray(size_t currentLineNumbersCount)
- {
- long long *sequence = (long long*)malloc(currentLineNumbersCount * sizeof(long long));
- if (sequence == NULL) return NULL;
- return sequence;
- }
- /*
- Дефиниране на функция, която служи
- за преобразуване на числата от текущия ред на входния двумерен char масив
- в тип long long и да се присвоят на едномерния long long масив
- */
- bool longLongTryParse(char *currentLine, long long *sequence, size_t currentLineNumbersCount)
- {
- char *currentNumberAsString = strtok(currentLine, " "); // Чрез тази функция се взима низ до даден разделител
- for (size_t i = 0; i < currentLineNumbersCount; i++)
- {
- if (currentNumberAsString == NULL) return false;
- sequence[i] = atoll(currentNumberAsString);
- currentNumberAsString = strtok(NULL, " "); // Взимане на следващия низ
- }
- return true; // Преобразуването бе успешно
- }
- /*
- Дефиниране на процедура, която служи
- за извикането на процедурата за намирането на края на първата поредица
- и при случай на намиране на край, извиква процедурата за пренареждането едномерния long long масив
- */
- void orderTheNumbersInTheSequenceAndCheckIfTheyAreCorrect(long long *sequence, size_t numbersCount)
- {
- // Извеждане на масива в първоначалния му вариант
- fputs("\nBefore:\n", stdout);
- printSequence(sequence, numbersCount);
- // Извикване на процедура, която служи за намирането на края на първата поредица в едномерен long long масив
- orderSequence(sequence, numbersCount);
- // Извеждане на масива след сортировката, ако е имало
- fputs("\nAfter:\n", stdout);
- printSequence(sequence, numbersCount);
- fputc('\n', stdout);
- }
- /*
- Дефиниране на процедура, която служи
- за изкарване на едномерен long long масив в конзолата
- */
- void printSequence(long long *sequence, size_t numbersCount)
- {
- for (size_t i = 0; i < numbersCount; i++)
- {
- fprintf(stdout, "%lld", sequence[i]);
- if (i < (numbersCount - 1))
- {
- fputc(' ', stdout);
- }
- }
- }
- /*
- Дефиниране на процедура, която служи
- за намирането на края на първата поредица в едномерен long long масив
- */
- void orderSequence(long long *sequence, size_t numbersCount)
- {
- for (size_t i = 1; i < numbersCount; i++)
- {
- if (sequence[i] < sequence[i - 1])
- {
- shiftToTheRightWithOneIndex(sequence, i);
- break;
- }
- }
- }
- /*
- Дефиниране на процедура, която служи
- за изместване на всеки елемент от едномерен long long масив с 1 индекс надясно
- */
- void shiftToTheRightWithOneIndex(long long *sequence, size_t dividerIndex)
- {
- for (size_t i = dividerIndex; i > 0; i--)
- {
- /*
- Разменят се елементите на позициите i и i - 1
- Обяснение:
- Тук се използва битовият оператор XOR за размяната на текущия елемент с предходния.
- Забележка:
- Методът XOR работи само ако стойностите в масива са цели числа.
- Ако числата са дробни, ще е нужно да се използва помощна променлива.
- */
- sequence[i] ^= sequence[i - 1];
- sequence[i - 1] ^= sequence[i];
- sequence[i] ^= sequence[i - 1];
- }
- }
- /*
- Дефиниране на процедура, която служи
- за сравнение на числата от едномерен long long масив с тези от изходния двимерен char масив,
- които се преoбразвуат в тип long long
- */
- void compareTheExpectedOutputsWithTheOutputsFromTheProgram(long long *sequence, char **expectedOutputs, bool *resultsCheck, size_t currentLineIndex, size_t currentLineNumbersCount)
- {
- char *currentNumberAsString = strtok(expectedOutputs[currentLineIndex], " ");
- for (size_t i = 0; i < currentLineNumbersCount; i++)
- {
- if (sequence[i] != atoll(currentNumberAsString))
- {
- resultsCheck[i] = false;
- break;
- }
- currentNumberAsString = strtok(NULL, " ");
- }
- }
- /*
- Дефиниране на процедура, която служи
- за изкарването на резултатите от сравненията
- межди изходите от програмата и изходния двумерен char масив в конзолата
- */
- void printResults(bool *resultsCheck, size_t linesCount, const char *prompt, const char *promptTwo)
- {
- fputs(prompt, stdout);
- for (size_t i = 0; i < linesCount; i++)
- {
- fprintf(stdout, "%s%s #%02zu %s!%s\n\n", resultsCheck[i] ? greenColouredText : redColouredText, promptTwo, i + 1, resultsCheck[i] ? "passed" : "failed", normalColouredText);
- }
- }
- /*
- Дефиниране на функция, която служи
- за повторно заделяне на памет на указател към променлива от тип char
- */
- char* reallocateMemoryForTheBuffer(char *buffer, size_t neededBufferSize)
- {
- char *newBuffer = (char*)realloc(buffer, neededBufferSize);
- if (newBuffer == NULL)
- {
- free(buffer);
- return NULL;
- }
- return newBuffer;
- }
- /*
- Дефиниране на процедура, която служи за извикването на процедурите,
- които премахват ненужните whitespace символи преди и след низа,
- разделителите и се заменят с празно място
- */
- void trim(char *currentLine, size_t currentLength)
- {
- // Извикване на процедура, която служи служи за премахването на ненужните whitespace символи преди и след низа
- trimLeadingAndTrailingWhitespaces(currentLine, currentLength);
- // Извикване на процедура, която служи за премахвато на разделителите и се заменят с празно място
- removeDelimiters(currentLine, currentLength);
- }
- /*
- Деклариране на процедура, която служи служи
- за премахването на ненужните whitespace символи преди и след низа
- */
- void trimLeadingAndTrailingWhitespaces(char *currentLine, size_t currentLength)
- {
- /*
- Деклариране на указател към тип char,
- който служи за премахването на whitespace символите преди първия не такъв символ
- */
- char *start = currentLine;
- while ( isspace((unsigned char)*start) && (start < (currentLine + currentLength)) )
- {
- start++;
- }
- /*
- Деклариране на указател към тип char,
- който служи за премахването на whitespace символите след последния не такъв символ
- */
- char *end = currentLine + currentLength - 1;
- while ( isspace((unsigned char)*end) && (end >= start) )
- {
- end--;
- }
- // Проверка дали низът съдържа само whitespace символи
- if (start > end)
- {
- currentLine[0] = '\0';
- fputs("Error: Empty line!\n", stdout);
- return;
- }
- /*
- Извикване на функция, която премества част от низ, за да премахне ненужните whitespace символи
- от началото и края на текущия низ.
- Функцията memmove копира част от низ от указателя "start" до указателя "end",
- включително последния символ, определен от "end".
- Параметрите на memmove:
- - текущият низ (currentLine) се променя и започва от "start".
- - "start" е указател към първия не whitespace символ.
- - "end - start + 1" е дължината на новия низ, която включва индекса на
- последния символ "end", минус индекса на първия символ "start", плюс 1
- за да бъде включен и последният символ на "end" в копирането.
- Функцията memmove не връща стойност, а променя директно данните в текущия низ.
- */
- memmove(currentLine, start, end - start + 1);
- currentLine[end - start + 1] = '\0'; // Слагане на край на низа
- }
- /*
- Дефиниране на процедура, която служи
- за премахването на разделителите и се заменят с празно място
- */
- void removeDelimiters(char *currentLine, size_t currentLength)
- {
- char *currentLineStart = currentLine;
- char *result = currentLine;
- bool inNumber = false;
- while (*currentLine)
- {
- /*
- Проверка дали текущият символ е число
- или символът '-' и число, следващо след него,
- и или е на първа позиция в масива, или символът ' ' (празно място) стои преди него
- */
- if (checkIfPartOfNumber(currentLine, currentLineStart))
- {
- *result++ = *currentLine++;
- inNumber = true;
- }
- else if ( checkIfDelimiter(delimiters, *currentLine) || isspace(*currentLine) )
- {
- if (inNumber)
- {
- *result++ = ' ';
- inNumber = false;
- }
- currentLine++;
- }
- }
- *result = '\0'; // Слагане на край на низа
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement