Progress Bar in C for an arbitrary long execution -- CONSOLE - c

I have tried my best to search not only stackOverflow but other website as well but could not find something to match my needs. What I am requesting is to be able to display a progress bar (e.g. Progress: ####.........). I don't really care for the % at the moment.
Now lies the problem. I can not simply do a 0-100 for loop as the code I wish to have executed and tracked lies within a while loop that runs for an arbitrary time (problem size depends on input of user thus, is not constant).
I have thought of keeping track of the number of iterations within an int variable and try to do a modulo by 2, 50 or 100 but as I have said, the number of iterations depends on the users input and thus, only manageable under specific conditions. No other output but the progress bar is done so I do a simple printf('#'); inside the while loop and all the pretty stuff outside it.
This is also a personal preference but don't mind if not included, I would like the progress bar to be 50 characters long so 100% execution = 50 '#' characters accordingly.
Any help is kindly appreciated.

So i wrapped the code from before nicelly and here is what i ended up with.
I used a little bit of oop concept and simulated the class of a ProgressBar. Here is how i designed the code for the ProgressBar:
struct tagProgressBarData
{
unsigned long nMaxLen;
unsigned long nCurLen;
char FillChr;
char EmptyChr;
char LeftMargin;
char RightMargin;
};
typedef struct tagProgressBarData PBD;
void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty);
void DrawProgressBar(PBD* p);
Before jumping to the definitions of InitProgressBar() and DrawProgressBar(), this is how you should use what i've made. Here is an example:
int main()
{
PBD data;
/** You can chose other characters and change the length too! */
InitProgressBar(&data, 50, '[', ']', '#', '.');
/** Now we do something which takes some time. */
/** Let's just calculate some random cubes. */
/** The N you talked about. */
unsigned int N;
printf("How many numbers to compute: ");
scanf("%u", &N);
printf("Calculating the cubes of the first %u numbers.\n", N);
DrawProgressBar(&data);
for(unsigned int i = 1; i <= N; i++)
{
unsigned int CubeResult = i*i*i;
unsigned long nProgress = ( ((unsigned long long)i) * data.nMaxLen) / N;
if (nProgress != data.nCurLen)
{
data.nCurLen = nProgress;
DrawProgressBar(&data);
}
}
return 0;
}
And now, the definition of the function that prints the progress bar:
void DrawProgressBar(PBD* p)
{
/** Move to the beginning of the line. */
printf("\r");
/** Print the left margin char. */
printf("%c", p->LeftMargin);
/** Make sure that MaxLen >= CurLen */
if (p->nMaxLen < p->nCurLen)
p->nCurLen = p->nMaxLen;
/** Print the progress with the Fill char. */
for(unsigned long i = 0; i < p->nCurLen; i++)
printf("%c", p->FillChr);
/** Complete whats left with the Fill char. */
for(unsigned long i = 0; i < p->nMaxLen - p->nCurLen; i++)
printf("%c", p->EmptyChr);
/** Print the right margin char. */
printf("%c", p->RightMargin);
}
I have also used this function to make my code in main more compact:
void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty)
{
p->nMaxLen = MaxLen;
p->nCurLen = 0;
p->LeftMargin = Left;
p->RightMargin = Right;
p->FillChr = Fill;
p->EmptyChr = Empty;
}
If you want to have some text before the progress bar but on the same line (something like Progress: [######.............]) you have to replace the printf("\r"); from the DrawProgressBar() with a for loop so you move back exactly the length of the progress bar.
Also, you need some variable (let's say bDrawn) which will tell you if the progress bar has been drawn at least once, so that the for loop will not move the cursor over the existing text at the left of the progress bar.

After trial and error, I may have found a solution but would like to check against someone.
Assuming these variables (all of type int):
num_iterations = 0, MAX_PROGRESS = 100, BAR_LENGTH = 50, num_items = N
I have printed a '#' character on:
if ((iteration / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items) == 0)
and get my desired result:
|<------------- Enumeration Complete ------------->|
|##################################################| COMPLETED
Though this gradually builds up, it is not of the form
|<------------- Enumeration Complete ------------->|
|##################################................|
Anything I can do with \r or \b?

I have also done this but seems to be very dependent on the number of items.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int MAX_PROGRESS = 100;
int BAR_LENGTH = 0; // Length of Header
int num_items = 30;
void delay(int milliseconds) {
// Storing start time
clock_t start_time = clock();
// looping till required time is not achieved
while (clock() < start_time + milliseconds);
}
void initialiseProgressBar(char left, char right, char fill) {
printf("%c", left);
for (int i = 0; i < BAR_LENGTH; i ++) {
printf("%c", fill);
}
/** Print the right first (end of line) and then again the left (start of line)
* as the \r will be placed over it and rewrite from there resulting in one
* character less
*/
printf("%c\r%c", right, left);
}
void drawProgressBar(char c) {
// Print according to BAR_LENGTH
for (int i = 0; i < 100; i ++) {
double progress = (i / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items);
if (progress == 0) {
printf("%c", c);
delay(25);
}
// Redraw the stdout stream to show progressing bar
fflush(stdout);
}
}
int main(int argc, char* argv[]) {
// Header
char* header = "|<------------- Progress Bar ------------->|\n";
printf("%s", header);
BAR_LENGTH = strlen(header) - 3; // Account for newline and right character characters
initialiseProgressBar('[', ']', '.');
drawProgressBar('#');
// Footer -- TODO Find better way to finish this without hard coding
printf("] COMPLETED\n");
return 0;
}
Assuming you know the number of items you are calculating against (e.g. sorting a list, calculating different things etc), this should come in handy :).

Related

Shuffle words from a 1D array

I've been given this sentence and I need to shuffle the words of it:
char array[] = "today it is going to be a beautiful day.";
A correct output would be: "going it beautiful day is a be to today"
I've tried many things like turning it into a 2D array and shuffling the rows, but I can't get it to work.
Your instinct of creating a 2D array is solid. However in C that's more involved than you might expect:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
int main()
{
char array[] = "today it is going to be a beautiful day.";
char out_array[sizeof(array)];
char words[sizeof(array)][46];
int word_count = 0;
int letter_count = 0;
int on_word = 0;
int count = 0;
int i = 0;
int j = 0;
srand(time(NULL));
// parse words into 2D array
for (i = 0; i < sizeof(array); i++) {
if (array[i] == ' ') {
if (on_word) {
words[word_count++][letter_count] = '\0';
letter_count = 0;
on_word = 0;
}
} else if (array[i] == '\0' || array[i] == '.') {
break;
} else {
on_word = 1;
words[word_count][letter_count++] = array[i];
}
}
words[word_count++][letter_count] = '\0';
// randomly swap around words
for (i = 0; i < word_count; i++) {
char temp[46];
int idx = rand() % word_count;
if (idx != i) {
strcpy(temp, words[idx]);
strcpy(words[idx], words[i]);
strcpy(words[i], temp);
}
}
// output words into out_array
for (i = 0; i < word_count; i++) {
for (j = 0; words[i][j] != '\0'; j++) {
out_array[count++] = words[i][j];
}
out_array[count++] = ' ';
}
out_array[count - 1] = '\0';
printf("%s", out_array);
return 0;
}
You need two basic algorithms to solve this problem.
Split the input string into a list of words.
Randomly sample your list of words until there are no more.
1. Split the input string into a list of words.
This is much simpler than you may think. You don’t need to actually copy any words, just find where each one begins in your input string.
today it is going to be a beautiful day.
^---- ^- ^- ^---- ^- ^- ^ ^-------- ^--
There are all kinds of ways you can store that information, but the two most useful would be either an array of integer indices or an array of pointers.
For your example sentence, the following would be a list of indices:
0, 6, 9, 12, 18, 21, 24, 26, 36
To do this, just create an array with a reasonable upper limit on words:
int words[100]; // I wanna use a list of index values
int nwords = 0;
 
char * words[100]; // I wanna use a list of pointers
int nwords = 0;
If you do it yourself either structure is just as easy.
If you use strtok life is much easier with a list of pointers.
All you need at this point is a loop over your input to find the words and populate your list. Remember, a words is any alphabetic or numeric value (and maybe hyphens, if you want to go that far). Everything else is not a word. If you #include <ctype.h> you get a very handy function for classifying a character is “word” or “not-word”:
if (isalnum( input[n] )) its_a_word_character;
else its_not_a_word_character_meaning_we_have_found_the_end_of_the_word;
Now that you have a list of words, you can:
2. Randomly sample your list of words until there are no more.
There are, again, a number of ways you could do this. Already suggested above is to randomly shuffle the list of words (array of indices or array of pointers), and then simply rebuild the sentence by taking the words in order.
→ Beware, Etian’s example is not a correct shuffle, though it would probably go unnoticed or ignored by everyone at your level of instruction as it will appear to work just fine. Google around “coding horror fisher yates” for more.
The other way would be to just select and remove a random word from your array until there are no words left.
The random sampling is not difficult, but it does require some precise thinking, making this the actually most difficult part of your project.
To start you first need to get a proper random number. There is a trick to this that people are generally not taught. Here you go:
int random( int N ) // Return an UNBIASED pseudorandom value in [0, N-1].
{
int max_value = (RAND_MAX / N) * N;
int result;
do result = rand(); while (result >= max_value);
return result % N;
}
And in main() the very first thing you should do is initialize the random number generator:
#include <stdlib.h>
#include <time.h>
int main()
{
srand( (unsigned)time( NULL ) );
Now you can sample / shuffle your array properly. You can google "Fisher-Yates Shuffle" (or follow the link in the comment below your question). Or you can just select the next word:
while (nwords)
{
int index = random( nwords );
// do something with word[index] here //
// Remove the word we just printed from our list of words
// • Do you see what trick we use to remove the word?
// • Do you also know why this does not affect our random selection?
words[index] = words[--nwords];
}
Hopefully you can see that both of these methods are essentially the same thing. Whichever you choose is up to you. I personally would use the latter because of the following consideration:
Output
You can create a new string and then print it, or you can just print each word directly. As the homework (as you presented it) does not require generation of a new string, I would just print the output directly. This makes life simpler in the sense that you do not have to mess with another string array.
As you print each word (or append it to a new string), remember how you separated them to begin with. If you use strtok you can just use something like:
printf( "%s", words[index] ); // print word directly to stdout
 
strcat( output, words[index] ); // append word to output string
If you found the beginnings of each word yourself, you will have to again loop until you find the end of the word:
// Print word, character by character, directly to stdout
for (int n = index; isalnum( words[index+n] ); n++)
{
putchar( words[index+n] );
}
 
// Append word, character by character, to output string
for (int n = index; isalnum( words[index+n] ); n++)
{
char * p = strchr( output, '\0' ); // (Find end of output[])
*p++ = words[index+n]; // (Add char)
*p = '\0'; // (Add null terminator)
}
All that’s left is to pay attention to spaces and periods in your output.
Hopefully this should be enough to get you started.

Fixing small error in output using arrays in C

I am currently working on a project that when given a main function which calls another function confab(), outputs a serious of characters. The question refers to some made up race. They choose an integer nRows between 2 and half the length of the message, e.g. a message of length 11 would allow values of nRows in the range 2 to 5. The message is then written down the columns of a grid, one character in each grid cell, nRows in each column, until all message characters have been used. This may result in the last column being only partially filled. The message is then read out row-wise.
For example the message "Don't wait until the last day before starting" with a nRows of 3 would return:
D'wtnlhltabo ai.ota t ea yersrnn iuit sd fettg
I have written code that does this fairly efficiently, however I have been provided with a test case that i cannot seem to work out.
char buffer[8] = {'*','*','*','*','*','*','*','*',};
confab("ABCDEF.", 3, buffer);
printf("%s\n", buffer);
Is this example, and the output it should give is:
AD.BECF
However my code returns:
AD.BECF*
Due to the extra * in the outText buffer not being replaced with a character. I have tried many things such as removing this extra *, or re initializing the outText to be the same length as the inText (within the code as the main case provided is not allowed to be edited), however nothing thus far has made a difference.
I was wondering if there would be a quick edit I could apply to my code that would perform this change, as I cannot seem to find a way apart from editing the main input which is not allowed.
My code is as follows:
/*
* Confabulons.c
* A program to encode for the Confabulons
*
* August 8th 2015
*/
#include <stdio.h>
#include <string.h>
//A simple function confab which given input text, and a number
//of rows, returns a phrase in the Confabulons encoding scheme.
void confab(const char inText[], int nRows, char outText[])
{
int count = 0;
int i = 0;
int z = 0;
int len = strlen(inText);
while (z < nRows)
{
while (((int)inText[count] > 0) && (count < len))
{
outText[i] = inText[count];
i ++;
count = count + nRows;
}
z ++;
count = z;
}
}
At the end of the function add line:
outText[i] = '\0';
You need to validate the length of the outText string, try:
void confab(const char inText[], int nRows, char outText[])
{
int count = 0;
int i = 0;
int z = 0;
int len = strlen(inText);
int lenOut = strlen(outText);
while (z < nRows)
{
while (((int)inText[count] > 0) && (count < len))
{
outText[i] = inText[count];
i ++;
count = count + nRows;
}
z ++;
count = z;
}
if (i < lenOut) {
outText[i] = '\0';
}
}

Recursively printing out the sections and subsections of an outline

Recursion is the one thing I have loads of trouble with. For this assignment we are supposed to print out an outline of sections and sub-sections. Take the following as an example.
Section 1
Section 1.A
Section 1.A.1
Section 1.A.2
Section 1.B
Section 1.B.1
Section 1.B.2
Section 2
Section 2.A
Section 2.A.1
Section 2.A.2
Section 2.B
Section 2.B.1
Section 2.B.2
This example has a depth of 3 and height of 2.
Here is my code thus far, which doesn't come anywhere near the correct output.
void printDepth(int depth, int width, int minusDepth, int minusWidth) {
int i = 0;
if(depth == 0)
printf("Section XX\n");
else {
printf("\t");
printDepth(depth -1, width, minusDepth, minusWidth);
}
}
Here is the call from main()
int minusDepth = 0;
int minusWidth = 0;
printDepth(depth, width, minusDepth, minusWidth);
However, for a depth = 4 and width = 5 this only prints out:
\t\t\t\tSection XX
I'm really not sure how to proceed. Recursion is the bane of my existence.
You need a loop that prints the sections at the current depth and executes height (which I call width instead) recursions. You also need to pass a string containing the current prefix of the section string.
#include <stdio.h>
#include <assert.h>
#include <math.h>
#define MAX_DEPTH 100
#define MAX_WIDTH 99 // NOTE: if you increase this then section's decl in printDepth needs to be updated too
void printDepth_r(int currDepth, int depth, int width, char *section, char *sub)
{
if (currDepth == depth) // recursion base case
return;
for (int i = 0; i < width; ++i)
{
// TODO: write to sub the subsection determined by (currDepth, width)
fprintf(stdout, "%*sSection %s\n", currDepth * 2, "", section);
// TODO: append "." to sub for descendant recursions
printDepth_r(currDepth + 1, depth, width, section, sub + /* TODO: num chars written to sub */);
}
}
int printDepth(int depth, int width)
{
char section[MAX_DEPTH * (2 + 1) + 1]; // NOTE: 2 == 1 + (int) (log(99) / log(10));
assert(sizeof(section) >= MAX_DEPTH * (1 + (int) (log(MAX_WIDTH) / log(10)) + 1) + 1);
if (depth > MAX_DEPTH || width > MAX_WIDTH)
return -1;
printDepth_r(0, depth, width, section, section);
return 0;
}
int main(int argc, char **argv)
{
printDepth(3, 2);
return 0;
}
Note that we pass the same values of depth, width and section to all of our recursions. So, if we wanted to reduce the amount of stack space the recursion eats at every level, then we could pull these out into a structure and pass 1 struct pointer to these 3 constants instead. Or, even better, we could store these values in thread local storage. Either way would allow deeper recursions before overflowing your stack.
#include <stdio.h>
void printDepth(int deep, int depth, int height, char *table) {
if(deep == depth)
return ;
int i, j;
char bak = table[deep];
for(i = 0; i < height; ++i){
printf("%*s%s", deep*2, "", "Section ");
for(j = 0; j <= deep; ++j){
if(j)
putchar('.');
putchar(table[j]);
}
putchar('\n');
printDepth(deep+1, depth, height, table);
table[deep]++;
}
table[deep] = bak;//restore
}
int main(void){
char table[] = "1A1";//Effective range up to 1-9 and A-Z
printDepth(0, 3, 2, table);
return 0;
}

Using recursion to print strings in C

Let me start with saying I am not looking for someone to do this for me. I am hoping for a hint or suggestion.
I know there is a smarter way to do this. Code is posted below. I am trying to print an outline. My code works up to a depth of 3. (The depth is the number of subsections - so 3 would be section 1, section 1.A, and section 1.A.1). It also works for a width (number of sections and each type of subsection) of 26, where it is capped. However, to get a larger depth, it would involve many more loops. Not only is that terrible code, it also freezes up the terminal I'm working on.
I believe recursion would make it much nicer, but I'm struggling to grasp the idea when using a string (I understand when it is a number).Thanks!
#include <stdio.h>
int sec(int width, int snum) {
char section[100];
sprintf(section, "Section ");
printf("%s %i", section, snum);
return 0;
}
int ssec_num(int width, int i) {
char num[100];
sprintf(num, "%i", i);
printf(".%s", num);
}
int ssec_let(int width, char z) {
char let[100];
sprintf(let, ".%c", z);
printf("%s", let);
}
int main(int argc, char* argv[]) {
int depth = atoi(argv[1]);
int width = atoi(argv[2]);
int sec_int=1;
int sec_wid = width;
int let_wid;
int num_int;
int num_dep;
int num_wid;
int dep;
char z = 'A';
while(sec_wid > 0) {
sec(width, sec_int);
let_wid = width;
dep = depth-1;
printf("\n");
while(dep > 0) {
while(let_wid > 0) {
num_wid = width;
num_int = 1;
sec(width, sec_int);
ssec_let(let_wid, z);
printf("\n");
num_dep = depth-2;
while(num_dep > 0) {
while(num_wid > 0) {
sec(width, sec_int);
ssec_let(let_wid, z);
ssec_num(width, num_int);
num_wid--;
num_int++;
printf("\n");
num_dep--;
}
}
let_wid --;
z++;
}
dep --;
}
sec_int++;
sec_wid--;
z = 'A';
}
}
If depth is 3 and width is 2 then it would be
Section 1
Section 1.A
Section 1.A.1
Section 1.A.2
Section 1.B
Section 1.B.1
Section 1.B.2
Section 2
Section 2.A
Section 2.A.1
Section 2.A.2
Section 2.B
Section 2.B.1
Section 2.B.2
The algorithm you described uses a width to declare how many times each (sub)section is repeated. This kind of repetition you can achieve with a loop.
The algorithm also uses a depth to determine how many (sub)sections you have. Here is the tricky part, and you can use recursion to solve it. A recursive function is basically a function that calls itself a limited number of times. There must always be a condition to stop the recursion, otherwise the function would call itself until the call stack overflows, abnormally stopping the program execution.
For your problem, you can have a function that receives a counter, that determines at with (sub)section depth it currently is. It would loop width times (as described above) and call itself depth times, until the counter reaches the value of depth. This way, you'll have a function that has a depth number of (sub)sections, each with a width number of items.
As you need to print the (sub)sections at the previous depths, you can use a buffer to store the section values at each depth, like int buffer[MAX_DEPTH];, with #define MAX_DEPTH 100 to set the maximum depth your program supports.
Then you'll have something like
#include <stdio.h>
#define MAX_DEPTH 100
void print_section(const int *const buffer, const int current_depth) {
// print all the (sub)section values stored at the buffer so far
// use a loop like for (i = 0; i <= current_depth; i++)
}
void recursive(int *const buffer, const int current_depth,
const int depth, const int width) {
if (current_depth < depth) {
// continue recursion
int current_width;
for (current_width = 1; current_width <= width; current_width++) {
buffer[current_depth] = current_width;
print_section(buffer, current_depth);
recursive(buffer, current_depth + 1, depth, width);
}
}
// else stop recursion
}
int main(int argc, char* argv[]) {
// ...
int buffer[MAX_DEPTH];
recursive(buffer, 0, depth, width);
return 0;
}
You'll also need some extra logic to determine when to print a letter or a number at each (sub)section depth.
EDIT: To print the (sub)section title just use the following
void print_section(const int *const buffer, const int current_depth) {
int i;
printf("Section ");
for (i = 0; i <= current_depth; i++) {
printf(i == 0 ? "%i" : ".%i", buffer[i]);
}
printf("\n");
}

How would I use this void function to calculate the percentage?

I am working with DNA strands, so an input string will look something like: ATGC (with the possible bases A, T, G, and C)
I have to utilize this function: void updateGCCount(char s[], int * gc, int * at) to calculate the percentage of "GC" content in the input string.
The function, updateGCCount, sweeps through the contents of the input string, s, and updates the "GC" and "AT" counts appropriately.
What I don't understand is, if this function doesn't return anything, if it's void, then how do I use this to calculate the percentage of "GC" content?
Here's my code for the updateGCCount function:
void updateGCCount(char s[], int * gc, int * at){
int i;
for(i=0;i!='\0';i++){
if(s[i]=='G' || s[i]=='C'){
(*gc)++; /*Updated with the help of people who answered!*/
}
if(s[i]=='A' || s[i]=='T'){
(*at)++; /*Updated with the help of people who answered!*/
}
}
}
And now here is my main function with the call to the above function (added this code on after receiving some help from the answers below):
int main(){
char s[400];
int gc, at;
double percentage;
scanf("%s", s);
gc = 0;
at = 0;
updateGCCount(s, &gc, &at);
percentage = (gc * 100.0)/(strlen(s) - 1);
printf("Sequence : %s\n", s);
printf("GC-content: %.2f\n", percentage);
return 0;
}
PROBLEMS I'M HAVING!
When I enter an input string of "ATCG", the percentage is 0 which isn't right and I can't figure out why it's giving me this problem! Help is greatly appreciated!
Thanks!
You need to increment what gc and at point at:
(*gc)++;
(*at)++;
As it stands, you keep incrementing the pointers themselves, which may lead to problems (though, since you don't actually dereference the pointers, it may not lead to major problems).
You might call it with:
char *dna = ...;
int gc = 0;
int at = 0;
updateGCCount(dna, &gc, &at);
Now you just have to determine what the percentage means. Is it the number of pairs of GC out of the total number of adjacent pairs, or some other specification (like the total number of either G or C compared to the total length of the DNA strand)?
It is likely that you count not pairs but single characters, so the percentage you're after becomes:
double percentage_gc = (gc * 100.0) / strlen(dna);
You also need to fix the test for end of string:
for (i = 0; s[i] != '\0'; i++)
int * gc is a pointer to a variable outside the function where the person calling the function wants the answer stored. You want to increment the value at that pointer:
(* gc) ++ ;
instead of
gc ++ ;
Also you are not looking at the string passed in, so this loop is never going to exit. Instead do:
int i; char c ;
for ( i= 0 ; ((c= s[i])) ; i ++ ) {
if ( c == 'G' || c == 'C' ) { (* gc) ++ ; }
etc.
You have fixed the problem with the pointers, but it's still not working.
You are not comparing "pairs", but individual characters; and your loop is all wrong. If you want to count "GC" (that is a G followed by a C), I think the following would work:
void updateGCCount(char s[], int * gc, int * at){
int i, Length;
Length = strlen(s); /* new terminating condition for the loop */
for( i = 0; i < Length - 1; i++ ) {
if(s[i]=='G' && s[i+1] =='C') {
(*gc)++; /* Updated with the help of people who answered! */
i++; /* if you found G followed by C, skip one */
}
if(s[i]=='A' && s[i+1]=='T') {
(*at)++; /* Updated with the help of people who answered! */
i++; /* if you found A followed by T skip one */
}
}
}

Resources