Skip to main content
Code Review

Return to Question

Notice removed Draw attention by Community Bot
Bounty Ended with no winning answer by Community Bot
edited tags; edited title
Link
200_success
  • 145.6k
  • 22
  • 190
  • 479

Interactive console application to edit a sorted list

Tweeted twitter.com/StackCodeReview/status/908003780687523840
Notice added Draw attention by machine_1
Bounty Started worth 50 reputation by machine_1
added 75 characters in body
Source Link
machine_1
  • 601
  • 6
  • 18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
struct G_list {
 char word[100];
 struct G_list *ptr;
};
typedef struct G_list G_list;
void add_and_sort(const char *str, G_list **head);
void free_list(G_list *head);
int cmp_at_begn(char *str, const char *substr);
void traverse_list(char *str, G_list *head);
void ClearScreen(void *hConsole);
int main(void)
{
 /* open file for reading and writing */
 const char filename[] = "Book.txt";
 FILE *fp = fopen(filename, "a+");
 if (!fp) {
 perror(filename);
 return 1;
 }
 /* ... */
 char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
 const size_t len = strlen(alphabet);
 /* allocate memory */
 G_list **wlist = (G_list **)malloc(sizeof(G_list *) * len);
 for (size_t i = 0; i < len; i++) {
 wlist[i] = (G_list *)malloc(sizeof(G_list));
 wlist[i]->ptr = NULL;
 wlist[i]->word[0] = 0;
 }
 /* load data from file */
 int c;
 char load[100];
 while (fgets(load, sizeof(load), fp)) {
 load[strcspn(load, "\n")] = 0;
 c = *load - 'a';
 if (c < 0 || c >= len) {
 continue;
 }
 add_and_sort(load, wlist + c);
 }
 /* recieve input and display data */
 int index = 0;
 char buf[100] = { 0 };
 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 while (1) {
 // if backspace, delete character and traverse list
 if (GetAsyncKeyState(VK_BACK) == -32767) {
 if (index) {
 buf[--index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 if (index) {
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 // if right-arrow key, discard input
 else if (GetAsyncKeyState(VK_RIGHT) == -32767) {
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if Enter, save to file
 else if (GetAsyncKeyState(VK_RETURN) == -32767) {
 if ((*buf - 'a') < 0 || (*buf - 'a') >= len) {
 continue;
 }
 add_and_sort(buf, &wlist[*buf - 'a']);
 fprintf(fp, "%s\n", buf);
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if escape, terminate the program
 else if (GetAsyncKeyState(VK_ESCAPE) == -32767) {
 break;
 }
 // accept alphabet-input and display matches if any
 for (short i = 'A'; i <= 'Z'; i++) {
 if (GetAsyncKeyState(i) == -32767) {
 buf[index++] = (char)(i + 32);
 buf[index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 /* release memory */
 fclose(fp);
 for (size_t i = 0; i < len; i++) {
 free_list(wlist[i]);
 }
 free(wlist);
}
void add_and_sort(const char *str, G_list **head)
{
 /* create node */
 G_list *node = (G_list *)malloc(sizeof(G_list));
 /* initialize node members */
 strcpy(node->word, str);
 node->ptr = NULL;
 /* ... */
 if ((*head)->word[0] == '0円') {
 *head = node;
 return;
 }
 else {
 while (1) {
 if (strcmp(str, (*head)->word) < 0) {
 G_list *tmp = *head;
 *head = node;
 node->ptr = tmp;
 break;
 }
 else {
 head = &((*head)->ptr);
 if (!*head) {
 *head = node;
 (*head)->ptr = NULL;
 break;
 }
 }
 }
 }
}
void free_list(G_list *head)
{
 G_list *tmp;
 while (head) {
 tmp = head;
 head = head->ptr;
 free(tmp);
 }
}
// compare at beginning of line
int cmp_at_begn(char *str,
 const char *substr)
{
 if (!*str || !*substr) {
 return (*str == *substr);
 }
 else {
 while (*str && *substr) {
 if (*str++ != *substr++) {
 return 0;
 }
 }
 }
 return !(*substr);
}
void ClearScreen(void *hConsole)
{
 COORD coordScreen = { 0, 0 }; // home for the cursor 
 DWORD cCharsWritten;
 CONSOLE_SCREEN_BUFFER_INFO csbi;
 DWORD dwConSize;
 // Get the number of character cells in the current buffer. 
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
 // Fill the entire screen with blanks.
 if (!FillConsoleOutputCharacter(hConsole, // Handle to console screen buffer 
 (TCHAR) ' ', // Character to write to the buffer
 dwConSize, // Number of cells to write 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten))// Receive number of characters written
 {
 return;
 }
 // Get the current text attribute.
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 // Set the buffer's attributes accordingly.
 if (!FillConsoleOutputAttribute(hConsole, // Handle to console screen buffer 
 csbi.wAttributes, // Character attributes to use
 dwConSize, // Number of cells to set attribute 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten)) // Receive number of characters written
 {
 return;
 }
 // Put the cursor at its home coordinates.
 SetConsoleCursorPosition(hConsole, coordScreen);
}
void traverse_list(char *str, G_list *head)
{
 int v = 0;
 while (head) {
 if (cmp_at_begn(head->word, str)) {
 puts(head->word);
 v = 1;
 }
 else {
 if (v) break;
 }
 head = head->ptr;
 }
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
struct G_list {
 char word[100];
 struct G_list *ptr;
};
typedef struct G_list G_list;
void add_and_sort(const char *str, G_list **head);
void free_list(G_list *head);
int cmp_at_begn(char *str, const char *substr);
void traverse_list(char *str, G_list *head);
void ClearScreen(void *hConsole);
int main(void)
{
 /* open file for reading and writing */
 const char filename[] = "Book.txt";
 FILE *fp = fopen(filename, "a+");
 if (!fp) {
 perror(filename);
 return 1;
 }
 /* ... */
 char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
 const size_t len = strlen(alphabet);
 /* allocate memory */
 G_list **wlist = (G_list **)malloc(sizeof(G_list *) * len);
 for (size_t i = 0; i < len; i++) {
 wlist[i] = (G_list *)malloc(sizeof(G_list));
 wlist[i]->ptr = NULL;
 wlist[i]->word[0] = 0;
 }
 /* load data from file */
 int c;
 char load[100];
 while (fgets(load, sizeof(load), fp)) {
 load[strcspn(load, "\n")] = 0;
 c = *load - 'a';
 if (c < 0 || c >= len) {
 continue;
 }
 add_and_sort(load, wlist + c);
 }
 /* recieve input and display data */
 int index = 0;
 char buf[100] = { 0 };
 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 while (1) {
 // if backspace, delete character and traverse list
 if (GetAsyncKeyState(VK_BACK) == -32767) {
 if (index) {
 buf[--index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 if (index) {
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 // if right-arrow key, discard input
 else if (GetAsyncKeyState(VK_RIGHT) == -32767) {
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if Enter, save to file
 else if (GetAsyncKeyState(VK_RETURN) == -32767) {
 add_and_sort(buf, &wlist[*buf - 'a']);
 fprintf(fp, "%s\n", buf);
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if escape, terminate the program
 else if (GetAsyncKeyState(VK_ESCAPE) == -32767) {
 break;
 }
 // accept alphabet-input and display matches if any
 for (short i = 'A'; i <= 'Z'; i++) {
 if (GetAsyncKeyState(i) == -32767) {
 buf[index++] = (char)(i + 32);
 buf[index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 /* release memory */
 fclose(fp);
 for (size_t i = 0; i < len; i++) {
 free_list(wlist[i]);
 }
 free(wlist);
}
void add_and_sort(const char *str, G_list **head)
{
 /* create node */
 G_list *node = (G_list *)malloc(sizeof(G_list));
 /* initialize node members */
 strcpy(node->word, str);
 node->ptr = NULL;
 /* ... */
 if ((*head)->word[0] == '0円') {
 *head = node;
 return;
 }
 else {
 while (1) {
 if (strcmp(str, (*head)->word) < 0) {
 G_list *tmp = *head;
 *head = node;
 node->ptr = tmp;
 break;
 }
 else {
 head = &((*head)->ptr);
 if (!*head) {
 *head = node;
 (*head)->ptr = NULL;
 break;
 }
 }
 }
 }
}
void free_list(G_list *head)
{
 G_list *tmp;
 while (head) {
 tmp = head;
 head = head->ptr;
 free(tmp);
 }
}
// compare at beginning of line
int cmp_at_begn(char *str,
 const char *substr)
{
 if (!*str || !*substr) {
 return (*str == *substr);
 }
 else {
 while (*str && *substr) {
 if (*str++ != *substr++) {
 return 0;
 }
 }
 }
 return !(*substr);
}
void ClearScreen(void *hConsole)
{
 COORD coordScreen = { 0, 0 }; // home for the cursor 
 DWORD cCharsWritten;
 CONSOLE_SCREEN_BUFFER_INFO csbi;
 DWORD dwConSize;
 // Get the number of character cells in the current buffer. 
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
 // Fill the entire screen with blanks.
 if (!FillConsoleOutputCharacter(hConsole, // Handle to console screen buffer 
 (TCHAR) ' ', // Character to write to the buffer
 dwConSize, // Number of cells to write 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten))// Receive number of characters written
 {
 return;
 }
 // Get the current text attribute.
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 // Set the buffer's attributes accordingly.
 if (!FillConsoleOutputAttribute(hConsole, // Handle to console screen buffer 
 csbi.wAttributes, // Character attributes to use
 dwConSize, // Number of cells to set attribute 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten)) // Receive number of characters written
 {
 return;
 }
 // Put the cursor at its home coordinates.
 SetConsoleCursorPosition(hConsole, coordScreen);
}
void traverse_list(char *str, G_list *head)
{
 int v = 0;
 while (head) {
 if (cmp_at_begn(head->word, str)) {
 puts(head->word);
 v = 1;
 }
 else {
 if (v) break;
 }
 head = head->ptr;
 }
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
struct G_list {
 char word[100];
 struct G_list *ptr;
};
typedef struct G_list G_list;
void add_and_sort(const char *str, G_list **head);
void free_list(G_list *head);
int cmp_at_begn(char *str, const char *substr);
void traverse_list(char *str, G_list *head);
void ClearScreen(void *hConsole);
int main(void)
{
 /* open file for reading and writing */
 const char filename[] = "Book.txt";
 FILE *fp = fopen(filename, "a+");
 if (!fp) {
 perror(filename);
 return 1;
 }
 /* ... */
 char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
 const size_t len = strlen(alphabet);
 /* allocate memory */
 G_list **wlist = (G_list **)malloc(sizeof(G_list *) * len);
 for (size_t i = 0; i < len; i++) {
 wlist[i] = (G_list *)malloc(sizeof(G_list));
 wlist[i]->ptr = NULL;
 wlist[i]->word[0] = 0;
 }
 /* load data from file */
 int c;
 char load[100];
 while (fgets(load, sizeof(load), fp)) {
 load[strcspn(load, "\n")] = 0;
 c = *load - 'a';
 if (c < 0 || c >= len) {
 continue;
 }
 add_and_sort(load, wlist + c);
 }
 /* recieve input and display data */
 int index = 0;
 char buf[100] = { 0 };
 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 while (1) {
 // if backspace, delete character and traverse list
 if (GetAsyncKeyState(VK_BACK) == -32767) {
 if (index) {
 buf[--index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 if (index) {
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 // if right-arrow key, discard input
 else if (GetAsyncKeyState(VK_RIGHT) == -32767) {
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if Enter, save to file
 else if (GetAsyncKeyState(VK_RETURN) == -32767) {
 if ((*buf - 'a') < 0 || (*buf - 'a') >= len) {
 continue;
 }
 add_and_sort(buf, &wlist[*buf - 'a']);
 fprintf(fp, "%s\n", buf);
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if escape, terminate the program
 else if (GetAsyncKeyState(VK_ESCAPE) == -32767) {
 break;
 }
 // accept alphabet-input and display matches if any
 for (short i = 'A'; i <= 'Z'; i++) {
 if (GetAsyncKeyState(i) == -32767) {
 buf[index++] = (char)(i + 32);
 buf[index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 /* release memory */
 fclose(fp);
 for (size_t i = 0; i < len; i++) {
 free_list(wlist[i]);
 }
 free(wlist);
}
void add_and_sort(const char *str, G_list **head)
{
 /* create node */
 G_list *node = (G_list *)malloc(sizeof(G_list));
 /* initialize node members */
 strcpy(node->word, str);
 node->ptr = NULL;
 /* ... */
 if ((*head)->word[0] == '0円') {
 *head = node;
 return;
 }
 else {
 while (1) {
 if (strcmp(str, (*head)->word) < 0) {
 G_list *tmp = *head;
 *head = node;
 node->ptr = tmp;
 break;
 }
 else {
 head = &((*head)->ptr);
 if (!*head) {
 *head = node;
 (*head)->ptr = NULL;
 break;
 }
 }
 }
 }
}
void free_list(G_list *head)
{
 G_list *tmp;
 while (head) {
 tmp = head;
 head = head->ptr;
 free(tmp);
 }
}
// compare at beginning of line
int cmp_at_begn(char *str,
 const char *substr)
{
 if (!*str || !*substr) {
 return (*str == *substr);
 }
 else {
 while (*str && *substr) {
 if (*str++ != *substr++) {
 return 0;
 }
 }
 }
 return !(*substr);
}
void ClearScreen(void *hConsole)
{
 COORD coordScreen = { 0, 0 }; // home for the cursor 
 DWORD cCharsWritten;
 CONSOLE_SCREEN_BUFFER_INFO csbi;
 DWORD dwConSize;
 // Get the number of character cells in the current buffer. 
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
 // Fill the entire screen with blanks.
 if (!FillConsoleOutputCharacter(hConsole, // Handle to console screen buffer 
 (TCHAR) ' ', // Character to write to the buffer
 dwConSize, // Number of cells to write 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten))// Receive number of characters written
 {
 return;
 }
 // Get the current text attribute.
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 // Set the buffer's attributes accordingly.
 if (!FillConsoleOutputAttribute(hConsole, // Handle to console screen buffer 
 csbi.wAttributes, // Character attributes to use
 dwConSize, // Number of cells to set attribute 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten)) // Receive number of characters written
 {
 return;
 }
 // Put the cursor at its home coordinates.
 SetConsoleCursorPosition(hConsole, coordScreen);
}
void traverse_list(char *str, G_list *head)
{
 int v = 0;
 while (head) {
 if (cmp_at_begn(head->word, str)) {
 puts(head->word);
 v = 1;
 }
 else {
 if (v) break;
 }
 head = head->ptr;
 }
}
Source Link
machine_1
  • 601
  • 6
  • 18

Interactive console application

I am reading a book that has some difficult vocabulary and I, in order to understand the book thoroughly, decided to collect and lookup those words am not acquainted with, spend sometime learning them, and re-read the book.

I have created an interactive console application specifically for this purpose. The program's main objectives are:

  • Open a file for reading and writing
  • Load data from file into linked list, if any, and sort them alphabetically.
  • Accept input from user, and search through the list for matches to display on screen.
  • If right key, is pressed, discard input. If Return key is pressed, save input to file, and if Escape key is pressed, cleanup and terminate program.

The key of interactivity is to show the user whether he added a word to the list or not, to avoid duplicates.

However, I have noticed that my implementation is hefty on the CPU, because when I run it, after short time, the fans become noisy, which make it hard for me to read and concentrate. Please advise on how can I optimize it and what improvements can be made.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
struct G_list {
 char word[100];
 struct G_list *ptr;
};
typedef struct G_list G_list;
void add_and_sort(const char *str, G_list **head);
void free_list(G_list *head);
int cmp_at_begn(char *str, const char *substr);
void traverse_list(char *str, G_list *head);
void ClearScreen(void *hConsole);
int main(void)
{
 /* open file for reading and writing */
 const char filename[] = "Book.txt";
 FILE *fp = fopen(filename, "a+");
 if (!fp) {
 perror(filename);
 return 1;
 }
 /* ... */
 char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
 const size_t len = strlen(alphabet);
 /* allocate memory */
 G_list **wlist = (G_list **)malloc(sizeof(G_list *) * len);
 for (size_t i = 0; i < len; i++) {
 wlist[i] = (G_list *)malloc(sizeof(G_list));
 wlist[i]->ptr = NULL;
 wlist[i]->word[0] = 0;
 }
 /* load data from file */
 int c;
 char load[100];
 while (fgets(load, sizeof(load), fp)) {
 load[strcspn(load, "\n")] = 0;
 c = *load - 'a';
 if (c < 0 || c >= len) {
 continue;
 }
 add_and_sort(load, wlist + c);
 }
 /* recieve input and display data */
 int index = 0;
 char buf[100] = { 0 };
 HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 while (1) {
 // if backspace, delete character and traverse list
 if (GetAsyncKeyState(VK_BACK) == -32767) {
 if (index) {
 buf[--index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 if (index) {
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 // if right-arrow key, discard input
 else if (GetAsyncKeyState(VK_RIGHT) == -32767) {
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if Enter, save to file
 else if (GetAsyncKeyState(VK_RETURN) == -32767) {
 add_and_sort(buf, &wlist[*buf - 'a']);
 fprintf(fp, "%s\n", buf);
 index = 0;
 *buf = '0円';
 ClearScreen(hStdout);
 continue;
 }
 // if escape, terminate the program
 else if (GetAsyncKeyState(VK_ESCAPE) == -32767) {
 break;
 }
 // accept alphabet-input and display matches if any
 for (short i = 'A'; i <= 'Z'; i++) {
 if (GetAsyncKeyState(i) == -32767) {
 buf[index++] = (char)(i + 32);
 buf[index] = '0円';
 ClearScreen(hStdout);
 printf("%s\n............\n", buf);
 traverse_list(buf, wlist[*buf - 'a']);
 }
 }
 }
 /* release memory */
 fclose(fp);
 for (size_t i = 0; i < len; i++) {
 free_list(wlist[i]);
 }
 free(wlist);
}
void add_and_sort(const char *str, G_list **head)
{
 /* create node */
 G_list *node = (G_list *)malloc(sizeof(G_list));
 /* initialize node members */
 strcpy(node->word, str);
 node->ptr = NULL;
 /* ... */
 if ((*head)->word[0] == '0円') {
 *head = node;
 return;
 }
 else {
 while (1) {
 if (strcmp(str, (*head)->word) < 0) {
 G_list *tmp = *head;
 *head = node;
 node->ptr = tmp;
 break;
 }
 else {
 head = &((*head)->ptr);
 if (!*head) {
 *head = node;
 (*head)->ptr = NULL;
 break;
 }
 }
 }
 }
}
void free_list(G_list *head)
{
 G_list *tmp;
 while (head) {
 tmp = head;
 head = head->ptr;
 free(tmp);
 }
}
// compare at beginning of line
int cmp_at_begn(char *str,
 const char *substr)
{
 if (!*str || !*substr) {
 return (*str == *substr);
 }
 else {
 while (*str && *substr) {
 if (*str++ != *substr++) {
 return 0;
 }
 }
 }
 return !(*substr);
}
void ClearScreen(void *hConsole)
{
 COORD coordScreen = { 0, 0 }; // home for the cursor 
 DWORD cCharsWritten;
 CONSOLE_SCREEN_BUFFER_INFO csbi;
 DWORD dwConSize;
 // Get the number of character cells in the current buffer. 
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
 // Fill the entire screen with blanks.
 if (!FillConsoleOutputCharacter(hConsole, // Handle to console screen buffer 
 (TCHAR) ' ', // Character to write to the buffer
 dwConSize, // Number of cells to write 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten))// Receive number of characters written
 {
 return;
 }
 // Get the current text attribute.
 if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
 {
 return;
 }
 // Set the buffer's attributes accordingly.
 if (!FillConsoleOutputAttribute(hConsole, // Handle to console screen buffer 
 csbi.wAttributes, // Character attributes to use
 dwConSize, // Number of cells to set attribute 
 coordScreen, // Coordinates of first cell 
 &cCharsWritten)) // Receive number of characters written
 {
 return;
 }
 // Put the cursor at its home coordinates.
 SetConsoleCursorPosition(hConsole, coordScreen);
}
void traverse_list(char *str, G_list *head)
{
 int v = 0;
 while (head) {
 if (cmp_at_begn(head->word, str)) {
 puts(head->word);
 v = 1;
 }
 else {
 if (v) break;
 }
 head = head->ptr;
 }
}
lang-c

AltStyle によって変換されたページ (->オリジナル) /