The use of tolower and storing in an array - c

I am trying to trace through this problem and can not figure out how the star is goes through the while loop and is stored in the array. Is * stored as 8 because of tolower? If anyone could please walk through the first for - to second for loop please I would be eternally grateful.
#include <stdio.h>
#include <ctype.h>
int main()
{
int index, freq[26], c, stars, maxfreq;
for(index=0; index<26; index++)
freq[index] = 0;
while ( (c = getchar()) != '7')
{
if (isalpha(c))
freq[tolower(c)-'a']++;
printf("%d", &freq[7]);
}
maxfreq = freq [25];
for (index = 24; index >= 0; index--)
{
if (freq[index] > maxfreq)
maxfreq = freq[index];
}
printf ("a b c d e f\n");
for (index = 0; index < 5; index++)
{
for (stars = 0; stars < (maxfreq - freq[index]); stars ++)
printf(" ");
for (stars = 0; stars < (freq[index]); stars++)
printf("*");
printf("%c \n", ('A' + index) );
printf(" \n");
}
return 0;
}

It seems that this code is a histogram of sorts that prints how many times a given character has been entered into the console before it reaches the character '7'.
The following code:
for(index=0; index<26; index++)
freq[index] = 0;
Is simply setting all of the values of the array to 0. This is because of the fact that in C, variables that are declared in block scope (that is, inside a function) and that are not static do not have a specific default value and as such simply contain the garbage that was in that memory before the variable was declared. This would obviously affect the results that are displayed each time it is run, or when it is run elsewhere, which is not what you want I'm sure.
while ( (c = getchar()) != '7')
{
if (isalpha(c))
freq[tolower(c)-'a']++;
printf("%d", &freq[7]);
}
This next section uses a while loop to continue accepting input using getchar() (which gets the next character of input from STDIN in this case) until the character "7" is reached. This is due to the fact that assigning a value (such as "c = getchar()") allows the value to be used in such a way that it can be compared using "! = '7'". This allows us to continue looping until the character that is accepted from STDIN is equal to '7', after which the while loop will end.
Inside the loop itself, it's checking the value that has been entered using "isalpha()", which returns true if the character is an alphabetic letter. By using "tolower()" and returning that value to be subtracted by the character value of 'a', we are basically finding which character in the alphabet this is numerically. An example would be if we took the letter 'F'. Capital 'F' is stored as the value 70 in the background. tolower() checks to see if it is an uppercase character, and if it is, it returns the lowercase version of it (in this case, 'f' == 102). This value is then subtracted by 'a' (stored as 97) which returns the value 6 (which, when counting from 0, is the position of 'F' in the alphabet). This is then used to target that element of the array and to increment it, which tells us that another "F" or "f" has been entered.
maxfreq = freq [25];
for (index = 24; index >= 0; index--)
{
if (freq[index] > maxfreq)
maxfreq = freq[index];
}
This next section sets the variable "maxfreq" to the last value (how many times 'Z' was found), and iterates downwards, changing the value of maxfreq to the highest value that is found (that is, the largest number of any given character that is found in the array). This is later used to format the output to make sure that the letters line up correctly and the number of stars and spaces are correct.

Related

C program for calculating alphabetical strings

Task:
Create a function maxRepeatingLetter that receives a string and as a result returns the letter that is repeated the most times in the given string (if more than one letter meets the given condition, return the first letter of the English alphabet). It is assumed that there will be at least one letter in the string.
Code:
#include <stdio.h>
char maxRepeatingLetter(const char *s)
{
int i, max = 0, maxIndex = 0;
int letter[26] = {0};
const char *pom = s;
while (*pom != '\0')
{
if ((*pom >= 'a' && *pom <= 'z'))
{
letter[*pom - 97]++;
}
if (*pom >= 'A' && *pom <= 'Z')
{
letter[*pom - 65]++;
}
pom++;
}
for (i = 0; i < 26; i++)
{
if (letter[i] > max)
{
max =letter[i]; maxIndex = I;
}
return maxIndex + 65;
}
int main ()
{
printf("Most repeating letter is: %c",
maxRepeatingLetter("input for letter to repeat"));
return 0;
}
My current task is being able to explain the code above and how it works. And I need to input a minor change into it, for example, to add something to the code, or make it simpler. But not to lose the main functions the code has.
Is anyone willing to explain the code above in 2-3 lines? And if you could, assist me or hint me, or even show me, what changes to the code I could apply.
I can see that you have to distinguish lowercase and uppercase and you can have only letters not symbols such as ? | ^ ! ecc... so I'll try to give you some advice:
Try to indent the code, it will be more readable to an external eye.
Using the variable letter is a good idea but i don't get the point of using pom.
If you can use use the function strlen() from the library string.h, otherwise implementing it by yourself could be a good exercise.
letter[*pom - 97]++, letter[*pom - 65]++ and maxIndex + 65 are dependant from the ASCII table, try letter[*pom - 'a']++, letter[*pom - 'A']++ and maxIndex + 'A'.
The for loop doesn't work, you missed a brackets so the if isn't in the for.
The code explanation is pretty easy, first of all you use the arrayletter of 26 elements because in the alphabet we have 26 letters, so the i-th element correspond to the i-th letter of the alphabet.
You loop once on the string and save in the i-th element letter the number of occurrence of the i-th letter.
With the if in for loop you are simply finding the max in that array, once found it, you return the index of the max, the index is the letter occuring more often.
Sorry for my bad English tell me if you need more help.
It is very straightforward if you are looking for an explanation of the above code. I recommend using multiple prints to understand how things are happening. Here are my few tips.
function maxRepeatingLetter() is updating the counter table letter[] each time the character appears.
After that, the code tries to find the highest number in the counter table letter[].

Why is the concatenated string at the end totally different from what the code does?

The code below might seem big, but it's really simple. I wanted to make an exercise generator in C, which concatenates latex formatted strings, stored in the function local arrays.
But the output is totally not what I expected it to be. I might have done something wrong with the pointers, or some overflow somewhere.
Tried all the tips I could find on internet:
(1) Initialize a string with '\0' at position 0;
(2) Use a pointer to the string to pass to the function;
int create_exercise_string(char **s, int s_size) {
// The format of the exercise is x+n=m;
// ASCII 48-57 = '0' ... '9';
int exercises_left = 10;
char *exercise;
char operation_list[][2] = {"+\0", "-\0"};
char equal[] = "&=&"; // & is for centering on the item contained in latex;
char array_begin[] = "\\begin{eqnarray*}\n";
char array_end[] = "\\end{eqnarray*}";
char number[1];
strcat(*s, array_begin);
s_size -= strlen(array_begin);
//REMOVE
puts("before exercise generation");
while (exercises_left > 0 && s_size > 0) {
exercise = malloc(256);
if (!exercise) {
puts("allocating error, quitting...");
getchar();
exit(1);
}
exercise[0] = '\0';
// THE INTERESTED PART =================================================
if (exercises_left < 10)
strcat(exercise, "\\\\\n");
printf("exercise number %d\n", exercises_left);
strcpy(exercise, "x");
//add an operator
strcat(exercise, operation_list[rand() % 2]);
// add a number
number[0] = (rand() % 10) + 48;
strcat(exercise, number);
// add an equal
strcat(exercise, equal);
// add a number
number[0] = (rand() % 10) + 48;
strcat(exercise, number);
// END =================================================================
s_size -= strlen(exercise);
strcat(*s, exercise);
free(exercise);
exercises_left--;
}
//REMOVE
puts("exercise generation ended");
if (s_size < strlen(array_end)) {
puts("create_exercise_string: buffer overflow detected, quitting...");
getchar();
exit(1); // for now... will be substituted with proper code
}
else strcat(*s, array_end);
puts("allocation worked, returning in main");
return exercises_left; // 0 if succesfull;
}
I was expecting the output to be like this
\begin{eqnarray*}
x-9&=&3\\
x+3&=&12\\
x-2&=&3\\
... 7 other exercises
\end{eqnarray*}
But I actually get
\begin{eqnarray*}
x-5\end{eqnarray*}&=&9\end{eqnarray*}x-9\end{eqnarray*}&=&2\end{eqnarray*}x+3\end{eqnarray*}&=&1\end{eqnarray*}x-7\end{eqnarray*}&=&0\end{eqnarray*}x+6\end{eqnarray*}&=&1\end{eqnarray*}x-6\end{eqnarray*}&=&5\end{eqnarray*}x+6\end{eqnarray*}&=&8\end{eqnarray*}x-8\end{eqnarray*}&=&6\end{eqnarray*}x+4\end{eqnarray*}&=&5\end{eqnarray*}x+1\end{eqnarray*}&=&5\end{eqnarray*}\end{eqnarray*}
With no \n added overall, and some \end{eqnarray*} repeatedly added...
What is wrong?
I managed to fix it.
All I can say is, when working with strings, always keep in mind if the terminating character is added or not, so in my case, I need to reinforce the study of strings allocation in C.
The problem was the variable number[1].
number[0] = rand() % 10 + 48;
This code adds the char representation of a number between 0 and 9 [48,57] in ASCII.
But it doesn't add a terminating null character!
Everytime I concatenated number to the exercise string, it overflowed to another local variable which had the terminating null character, thus the "undefined behaviour" of strcat() was that it kept reading another local variable.
Lucky me in memory there was a '\0' minefield, otherwise I would have needed to bang my head on the wall, if protected memory was tried to be read.
Thanks for the help!

int variable changes to 1 after 'while' loop

I was trying to make a 'decimal to binary' program. It should convert from 0 to 255 only and it does.
I have two variables, 'n' and 'temp', when the user first enters the number I store it on 'n'. Then I assign 'n' to 'temp' (thus creating a copy, at least that's what I think I'm doing).
then I only use 'temp' in my code. I never use 'n', not until the end where I decide to print the number the user entered. And here comes the problem, if I enter a number greater than 255, the variable 'n' changes to 1.
I tried running my code through a couple C online compilers and all of them output the variable 'n' the right way, meaning that despite the binary not working when the numbers is greater than 255 (as intended) they print the entered value.
I found one online compiler where it doesn't print the 'n' variable if its greater than 255.
https://www.tutorialspoint.com/compile_c_online.php
If you run my code through this compiler, you'll see how the variable 'n' changes to 1 without it being used.
I know the 'binary part' won't work if you use a number greater than 255. I want to know why 'n' changes out of nowhere.
#include <stdio.h>
int main()
{
int bin[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int arrSize = 7;
int n;
int temp;
scanf("%d", &n);
temp = n;
while(temp != 0)
{
bin[arrSize] = temp % 2;
temp = temp / 2;
arrSize = arrSize - 1;
}
printf(" Decimal: %d ----> binary: ", n);
for(int i = 0; i <= 7; i++)
{
printf("%d", bin[i]);
}
printf("\n");
return 0;
}
You've run through a "Buffer overflow".
A quick definition for that:
A buffer overflow occurs when a program or process attempts to write
more data to a fixed length block of memory, or buffer, than the
buffer is allocated to hold. Since buffers are created to contain a
defined amount of data, the extra data can overwrite data values in
memory addresses adjacent to the destination buffer unless the program
includes sufficient bounds checking to flag or discard data when too
much is sent to a memory buffer.
The error in your code remains in this while loop:
while(temp != 0){
//I added this line to make it clear
printf("inside loop\tarrSize=%d\n",arrSize);
bin[arrSize] = temp % 2;
temp = temp / 2;
arrSize = arrSize - 1;
}
For an input equals to 300 (The error will occur for each input > 255) you'll have this output:
inside loop arrSize=7
inside loop arrSize=6
inside loop arrSize=5
inside loop arrSize=4
inside loop arrSize=3
inside loop arrSize=2
inside loop arrSize=1
inside loop arrSize=0
inside loop arrSize=-1
inside loop arrSize=0
The problem is that we have an index equals to -1, You'll ask what will happen ? well in fact arrays are pointers to the address of the first element of the table + the offset (index * size of the type of the table) which means that for bin[-1] it is in fact arrSize, and bin[-2] is in fact n.
You can check this by verifying the addresses as it follows:
printf("# of bin[-1]:\t%p\n",(void*)&bin[-1]);
printf("# of arrSize:\t%p\n\n",(void*)&arrSize);
printf("# of bin[-2]:\t%p\n",(void*)&bin[-2]);
printf("# of n:\t\t\t%p\n",(void*)&n);
which with my compiler gave me:
# of bin[-1]: 0x7ffe00e32f9c
# of arrSize: 0x7ffe00e32f9c
# of bin[-2]: 0x7ffe00e32f98
# of n: 0x7ffe00e32f98
So you changes without knowing bin[-1] (or bin[-2] according to the value of n) which is in fact arrSize (or n)..
How you can fix this ? I advice you to verify the index every time you want to loop over an array (the condition of the loop must be in function of arrSize). Or you can if you want for this specific exemple to ignore that and focus on the logic: verify the input (in your case the input n must be: 0 <= n <= 255)
void *ieee2b(double value,char size,void *res){
char
*p0=res,
*p=p0;
vbreplacec(vbsprintf(p,"%*.*s",size,size," "),' ','0',p);
if((long)value!=value)
while(1){
double
tmp=value*2;
*p++='0'+(long)tmp;
if(tmp==1||tmp==0||p-p0>size)
break;
value=tmp-(long)tmp;
}
else{
p=p0+size-1;
while((long)value>1){
*p--='0'+((long)value%2);
value=(long)value/2;
}
*p--='0'+((long)value);
}
return res;
}

K&R 1.6 Array. Not understanding the code [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I start reading the book K&R The C programmming ( 2nd edition). And I got stuck on the 1.6 Array; I just can't seem to figure out what the code does (even tho it says it counts digits, white spaces and others!). Here is the code:
#include <stdio.h>
/* count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n",nwhite, nother);
}
So first it defines Integers, ( c,i,nwhite,nother);
After that it creates an array of 10 digits, ( 0 -9 )
After that it sets nwhite and nother to 0.
the for loops set I to 0, i < 10 means if its lower, add i = i + 1.
ndigit[i] = 0? I dont quite understand it, isnt i already is 0?
while ((c = getchar() != EOF) means What ever the input is and isnt at the end of the file?.
After that part I kinda got lost and I'm not sure what
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
Does at all.
And I don't quite understand why the for (i = 0; i < 10 ; +=i ) is repeated . I do understand English but some expensive use of words will confuse me. So if you dont mind, please keep it basic for me. I really hope there is someone out there who can help me understanding this code 100%. Because after all, who wants a programmer who cant even understand the code? :)
Let us step through the code and see what is happening.
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
In the first first line of code we are declaring[0] (to the compiler) that c, i, nwhite and nother will be integer variables. At this point, while we have declared these variables, we have not given them any value.
The next line we are declaring that ndigit will be an array of 10 integers, again no initialization is happening so we have no idea of what the value of those ten integers might be.
In the third line we are defining nwhite and nother to be zero, in other words we are initializing them to some value.
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
In this loop, we are initializing the variable i to be zero, and we will increment it by one ever time through the loop, till the value become ten or larger. The body of the loop sets each element of the array to zero. This is a common c-idiom for initializing the elements of an array.
while ((c = getchar()) != EOF)
{
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
}
The next block of code does the actual counting. While the code in K&R is syntactically correct, I prefer enclosing the bode of the while loop with curly-braces, I find it easier to read, but it is a personal thing [1].
The condition of the while loop ((c = getchar()) != EOF), can be kind of confusing. We perform the operation in parenthesis first, which is c = getchar() which has the effect of getting the next character and assigning it to the variable c. (remember that in C a character (i.e. variable of type char), is just a small integer so we can assign a character type to an integer type). The assignment statement has a return value[2], in that it returns the value on the right side of the assignment operator, so the operation in parenthesis returns the value of getchar(), which is then compared to EOF, and if it doesn't equal EOF we enter the body of the while statement.
The first if statement checks to see if the character is a number. In ASCII, number have the value of 0x30 ('0') through 0x39 ('9'), so we check to see if the character is in that range. If it is, we increment the appropriate value in the ndigit array. For example, suppose that we have read in the character '5' which has an ASCII value of 0x35. Because 0x35 is between 0x30 and 0x39 we have a digit. Performing the subtraction c - '0' is equivalent to 0x35 - 0x30 which equals 0x05. We then use this as the index into the array, and increment the appropriate value with ++ndigit[c-'0'].
The next branch of the if-block, check to see if c is a a white space, i.e. the
expression c == ' ' || c == '\n' || c == '\t' check to see if c is a space or if c is a new-line or if c is a tab. If c is one of those characters we then
increment nwhite.
Finally, the else branch is taken if we do not have a digit or white space, and we then increment nother.
printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n", nwhite, nother);
}
The last bit of code just prints out the results. Because we want to look at all ten elements of the ndigit array, we need to step through the array again so we use the for loop structure to look at each element of the array.
Hopefully, this clears up some stuff. Something you may want to try is to modify this code so that it counts the of letters that are appearing in the input as well. First just try and count letters, with out regard to case, and then see if you can count upper and lower case letters.
notes:
[0] Declaring a variable is just specifying the name and type of the variable, so int x; is just a declaration. We are providing just enough information to the compiler that it can check our usage of x. A definition is when we assign a value to the variable, so x=5; is a definition. Note that the declaration and definition can be combined into a single line int x = 5;. At the assembly level, a declaration causes storage to be allocated for the variable, but does not set what the storage location contains.
[1] The C grammar says that the curly-braces are not needed for a while block if
it consists of a single statement, i.e.
while(n > 10)
c--;
and
while(n > 10)
{
c--;
}
are equivalent, I just find the second easier to read. Also, the C grammar
says that curly braces are not need for the body of an if statement if the body consists of a single statement, so for example
if(n < 10)
n = n - 10;
and
if(n < 10)
{
n = n - 10;
}
are equivalent.
Finally, the else if and end all are part of the if statement so the statement
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
is effectively a single statement, and thus why the curly braces are not needed.
Also, for readability and maintainability I tend to use curly braces with if / else if / else blocks - but again it is a personal think.
[2] The assignment statement has a return value of the left hand side, so a simple expression of a = 10; the return value is just ignored. Having a return value allows us to write something like, a = b = c = 10 which will have the effect of setting a, b and c to 10. In addition of having a return value, the assignment operator is right associative, so the above expression would be
interpreted as a = (b = (c = 10)).
-T.

keep getting ascii value where char is expected

When a coordinate is selected, it should be replaced with a "~". However, it's being replaced with the ascii value for the ~ instead (126). I tried a few different things, but I always get the 126 instead of the ~. Any ideas?
Thanks for the help!
int board_is_empty(int N, int board[ROWS][COLS])
{
int i = 0, j = 0;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
if (board[i][j] != '~')
{
return 0;
}
}
}
return 1;
}
//updates the board to replace each selected coordinate with a ~.
//returns nothing
void update_board (int board[ROWS][COLS], int row_target, int column_target)
{
board[row_target][column_target] = '~';
}
int main(void)
{
int game_board[ROWS][COLS] = {0};
int rows, columns = 0;
int players_turn = 1, target_column = -1, target_row = -1, value = 0;
int row_selection = 0, column_selection = 0;
int i = 0;
initialize_game_board(game_board);
display_board(game_board);
generate_starting_point(game_board, &rows, &columns);
printf ("\nPlease hit <Enter> to continue.\n");
getchar ();
while (board_is_empty(ROWS, game_board) != 1)
{
select_target (&target_row, &target_column, players_turn);
value += game_board[target_row][target_column];
update_board (game_board, target_row, target_column); //should cause the coordinates at target_row && target_column to be replaced with a ~
display_board(game_board);
}
printf("\n%d", value);
}
'~' is a character and you have declared board as a two dimensional integer array.
so when you write board[row_target][column_target] = '~';
it convert '~' it into integer i.e into its ascii value which is 126
and there for it becomes board[row_target][column_target] = 126
I will suggest make board as two dimensional character array. Hopefully it will solve your problem.
And in case if you want it as integer only then consider 126 as a special no which means '~' by declaring
For storing your coordinates, you are using an integer array. When you execute
board[row_target][column_target] = '~'; tilde's ascii value (126) is assigned to LHS. There is no way you can assign a character to an integer value. I think you should use some special number rather than tilde. If I were you, I would use INT_MIN or INT_MAX.
There isn't a difference between the character '~' and the number 126 as far as the C language is concerned, '~' == 126.
(You used "~" which i would normally use for a string, but i assume you don't actually mean that).
If you want to display a value, you have to use the correct format string. %d is for decimal integers, %c would be for characters (the variable holding the value should also be a char)
In C, chars are just integers. At output time they are represented as characters but internally they hold just the ASCII code of that character.
Since your board is a matrix of int's, when you assign '~' you are effectively assigning the number 126 to a position of the board. If you check that position, the expected result is to get an int equal to 126.
However, if you want to see that value as a character, you can do it by casting that number into a char:
printf("%c", value);
Take a look:
#include <stdio.h>
int main()
{
int i = '~';
char c = '~';
printf("Integer: %d\n", i); /* outputs: 126 */
printf("Char: %c\n", c); /* outputs: ~ */
printf("Integer casted to char: %c\n", i); /* outputs: ~ */
}
That is, your value is right. You just need to get the representation you want. (If you want to be able to store the value 126 in the board and the character ~ at the same time, then you're out of luck because for C they are the same thing -you can use some other value that you know that the board isn't going to hold, like -1 or something like that).
Update:
So, if I didn't get it wrong what you're trying to do is to read numbers from a bidimensional matrix of random integers and mark each one as you go reading them.
If that is what you're trying to achieve, then your idea of using '~' to mark the read positions isn't going to work. What I meant before is that, in C, 126 and the character '~' are the exact same thing. Thus, you won't be able to differentiate those positions in which you have written a '~' character and those ones in which a random 126 is stored by chance.
If you happen to be storing positive integers in your array, then use -1 instead of '~'. That will tell you if the position has been read or not.
If you are storing any possible random integer, then there is nothing you can store in that array that you can use to mark a position as read. In this case a possible solution is to define your array like this:
typedef struct {
int value;
char marked;
} Position;
Position board[ROWS][COLS];
Thus, for each position you can store a value like this:
board[row][col].value = 23123;
And you can mark it as read like this:
board[row][col].marked = 'y';
Just, don't forget to mark the positions as not read (board[row][col].marked = 'n';) while you fill the matrix with random integers.

Resources