How to find number of occurrences in array of chars in C? - c

I am trying to enter a word, and get how many times the letters were typed.
Say my input is "hello"
my output would be: h = 1, e = 1 l = 2 etc.
I am very close to getting it right, but I have a small issue with this code:
#include <stdio.h>
#include <string.h>
void find_frequency(char s[], int count[]) {
int c = 0;
while (s[c] != '\0') {
if (s[c] >= 'a' && s[c] <= 'z' )
count[s[c]-'a']++;
c++;
}
}
int main()
{
char string[100];
int c, count[26] = {0};
printf("Input a string\n");
gets(string);
find_frequency(string, count);
printf("Character Count\n");
for (c = 0 ; c < 26 ; c++)
if(count[c] > 0)
printf("%c : %d\n", c + 'a', count[c]);
return 0;
}
This code does half of the job, but not all.
It's output is in alphabetical order. How can i change it to give me an output of just the chararray that is input?

As Ry- suggested in this comment you could iterate back over the original string and use the chars as indices into your frequency table. Something like the following:
int len_string = strlen(string);
for (c=0; c<len_string; c++) {
char ch = string[c];
printf("%c: %d, ", ch, count[ch-'a']);
}
This won't completely match your expected output, since this code will output l: 2 twice, but that raises the question:
What is your expected output when you have a string like abba? a:2, b:2? a:1, b:2, a:1? a: 2, b:2, a:2? It's hard to help when you ask such an ambiguous question.

#include <stdio.h>
#include <string.h>
size_t ASCIIfreq[256];
void CountASCII(void *buff, size_t size)
{
unsigned char *charsptr = buff;
memset(ASCIIfreq, 0, sizeof(ASCIIfreq));
while(size--)
{
ASCIIfreq[*charsptr++]++;
}
}
void print(int printall)
{
for(size_t index = 0; index < 256; index++)
{
if(ASCIIfreq[index] || printall)
{
printf("The %03zu (0x%02zx) ASCII - '%c' has occured in the buffer %zu time%c\n",
index, index, (index > 32 && index < 127) ? (char)index : ' ',
ASCIIfreq[index], ASCIIfreq[index] == 1 ? ' ' : 's');
}
}
}
int main()
{
char teststring[] = "i am trying to enter a word, and get how many times the letters were typed. Say my input is \"hello\" my output would be: h = 1, e = 1 l = 2 etc.I am very close to getting it right, but i have a small issue with this code";
CountASCII(teststring, sizeof(teststring));
print(0);
return 0;
}

It's not clear what you mean by:
How can i change it to give me an output of just the chararray that is input?
Because that's exactly what you're doing in any case: Inputting a char array to the function; which is updated with numbers alphabetically; and later output as is.
So I'm guessing that you want to output the counts in the same order that each char was first encountered?
Solution
This will require a bit more work. You could keep a second array tracking the the order each character is encountered within find_frequency. But then that simple clean function starts doing too much.
So consider rather tweaking how you do the output:
void output_frequency(char s[], int count[]) {
int c = 0;
//loop s for the output
while (s[c] != '\0') {
if (s[c] >= 'a' && s[c] <= 'z' ) {
//found a character, report the count only if not reported before
if (count[s[c]-'a'] > 0) {
printf("%c : %d\n", s[c], count[s[c] - 'a']);
count[s[c]-'a'] = 0; //so you don't report this char again
}
}
c++;
}
}

If you are attempting to get an in-order count instead of a count in alphabetical order, you simply need to coordinate the indexes of your count array with the order of characters in your input buffer. To do that, simply loop over all characters in your input buffer and make a second pass counting the number of times the current character occurs. This will give you an in-order count of the number of times each character occurs, e.g.
#include <stdio.h>
#include <string.h>
#define COUNT 128
#define MAXC 1024
int main (void) {
char buf[MAXC] = ""; /* buffer to hold input */
int count[COUNT] = {0}; /* array holding inorder count */
fputs ("enter string: ", stdout); /* prompt for input */
if (!fgets (buf, MAXC, stdin)) { /* read line into buf & validate */
fputs ("error: EOF, no valid input.\n", stderr);
return 1;
}
/* loop over each character not '\n' */
for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
char *p = buf; /* pointer to buf */
size_t off = 0; /* offset from start of buf */
while ((p = strchr (buf + off, buf[i]))) { /* find char buf[i] */
count[i]++; /* increment corresponding index in count */
off = p - buf + 1; /* offset is one past current char */
}
}
for (int i = 0; count[i]; i++) /* output inorder character count */
printf (i ? ", %c: %d" : "%c: %d", buf[i], count[i]);
putchar ('\n'); /* tidy up with new line */
return 0;
}
(note: strchr is used for convenience to simply find the next occurrence of the current character within the string and then off (offset) is used to start the search with the following character until no other matches in the string are found. You can simply use an additional loop over the characters in the buffer if you like.)
Example Use/Output
$ /bin/charcnt_inorder
enter string: hello
h: 1, e: 1, l: 2, l: 2, o: 1
However, this does recount each character and give the count again if the character is duplicated, (e.g. l: 2, l: 2 for each 'l'). Now it is unclear from:
"my output would be: h = 1, e = 1 l = 2 etc."
what you intended in that regard, but with just a little additional effort, you can use a separate index and a separate array to store the first instance of each character (in say a chars[] array) along with the count of each in your count[] array and preserve your inorder count while eliminating duplicate characters. The changes needed are shown below:
#include <stdio.h>
#include <string.h>
#define COUNT 128
#define MAXC 1024
int main (void) {
char buf[MAXC] = "",
chars[COUNT] = ""; /* array to hold inorder chars */
int count[COUNT] = {0};
size_t cdx = 0; /* add count index 'cdx' */
fputs ("enter string: ", stdout);
if (!fgets (buf, MAXC, stdin)) {
fputs ("error: EOF, no valid input.\n", stderr);
return 1;
}
for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
char *p = buf;
size_t off = 0;
chars[cdx] = buf[i]; /* store in chars array */
if (i) { /* if past 1st char */
int n = i;
while (n--) /* simply check all before */
if (buf[n] == buf[i]) /* if matches current */
goto next; /* bail and get next char */
}
while ((p = strchr (buf + off, buf[i]))) {
count[cdx]++; /* increment count at index */
off = p - buf + 1;
}
cdx++; /* increment count index */
next:; /* goto label to jump to */
}
for (int i = 0; count[i]; i++)
printf (i ? ", %c: %d" : "%c: %d", chars[i], count[i]);
putchar ('\n');
return 0;
}
Example Use/Output
$ /bin/charcnt_inorder2
enter string: hello
h: 1, e: 1, l: 2, o: 1
or
$ ./bin/charcnt_inorder2
enter string: amarillo
a: 2, m: 1, r: 1, i: 1, l: 2, o: 1
Now your 'l' is only reported once with the correct count.
Note, in each example you should do additional validation to insure the entire input fit within your buffer, etc... The count (and chars) array were sized at 128 to cover the entire range of ASCII values. Don't skimp on buffer size. If you explicitly limit your input to UPPERcase or lowercase -- then you can limit your count size to 26, otherwise you need to consider the additional characters and punctuation that will be encountered. The same applies to your input buffer. If you anticipate you max input would be 500 chars, double it (generally to next available power of two, no real requirement for powers of two, but you are likely to see it that way).
Bottom line, I'd rather be 10,000 characters too long that one character too short... leading to Undefined Behavior.
Lastly, as mentioned in my comment never, never, never use gets. It is so insecure it has been removed from the C standard library in C11. Use fgets or POSIX getline instead.
Look things over and let me know if you have further questions.

Related

How can I get an input text to be printed in reverse, with a specified length to each output line

I need to write a code that takes a user input and outputs a mirror image of the input, with a line break every x characters, where x is a number input by the user.
For example:
Enter the length of the output line: 5
Enter your text (control-d to exit): Hello there
output:
olleH
.ereh
....t
12345
(the dots are spaces)
My current code is:
int main() {
char input[121], mirror[121];
int length = 0, i, str = 0, j = 2, reset = 0, k;
printf("Enter the width of an output line:\n");
scanf("%d", &length);
printf("Enter your text (control-d to exit):\n");
while (scanf("%c", &input[i]) == 1) {
i++;
}
reset = length;
str = strlen(input);
printf("\n");
input[str] = '\0';
for (i = 0; i < ((str / length) + 1); i++) {
for (k = 0; k < length; k++) {
if ((length - k) >= 0) {
mirror[k] = input[reset - k];
printf("%c", mirror[i]);
}
else if ((length - k) < 0) {
printf("\n");
mirror[k] = input[reset + 1];
reset = (j * reset);
j++;
}
}
}
return 0;
}
My output is nowhere near correct, and although I've had previous attempts that were closer to correct, overall I am not sure how to really approach this problem.
Your algorithm went off the rails, but we can get the train back up on the track. The key is to recognize you have to reverse each WORD in the string preserving whitespace and then output characters in groups of width characters at a time from your output array. If the final group has output that would be beyond the length of the string, output spaces and then the final characters.
That and cleaning up your code, validating all input and getting rid of scanf() that is full of pitfalls for the new C programmer, you could do the following:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXC 128 /* if you need a constant, #define one (or more) */
int main (void) {
char input[MAXC],
output[MAXC];
size_t length = 0, /* strlen returns size_t not int */
width = 0,
i = 0;
/* just reuuse the 'input' buffer to read width and use sscanf() for
* the conversion VALIDATING both by CHECKING THE RETURN.
*/
fputs ("Enter the width of an output line : ", stdout);
if (!fgets (input, MAXC, stdin) || sscanf (input, "%zu", &width) != 1) {
puts ("(user canceled input) or invalid integer input");
return 1;
}
/* read/validate input, trim \n and get length */
fputs ("Enter your text : ", stdout);
if (!fgets (input, MAXC, stdin)) {
puts ("(user canceled input)");
return 1;
}
input[strcspn (input, "\n")] = 0; /* trim \n from end */
length = strlen (input); /* get input length */
putchar ('\n'); /* use putchar() to output a single-character */
/* reverse words in input preserving whitespace */
for (i = 0; input[i];) { /* loop each char in input */
if (isspace (input[i])) { /* if space, copy to output */
output[i] = input[i];
i++; /* increment loop index */
}
else { /* otherwise, not space, get length of word, save index */
size_t wordlen = strcspn (input + i, " \t\n"),
index = i;
if (!wordlen) { /* if wordlen is zero, at end, break */
break;
}
while (wordlen--) { /* reverse loop wordlen filling output */
output[i++] = input[index + wordlen]; /* increment loop index */
}
}
}
output[i] = 0; /* nul-terminate output */
for (i = 0; i < length;) { /* loop while i < length */
size_t j = width; /* counter for width characters */
while (j--) { /* loop width number of times */
if (j + i >= length) { /* if i + j outside string put space */
putchar (' ');
}
else { /* otherwise */
putchar (output[i++]); /* output next char in output */
}
}
putchar ('\n'); /* tidy up with newline */
}
}
(note: you can trim the '\n' and save the length in a single call with input[(length = strcspn (input, "\n"))] = 0;, but up to you)
Also note, the last if-else can be considerably shortened using a ternary operator. That would reduce the final comparison to:
putchar (j + i >= length ? ' ' : output[i++]);
Up to you which you want to use.
Example Use/Output
Now your example output is correctly reproduced, e.g.
$ ./bin/revstr
Enter the width of an output line : 5
Enter your text : Hello there
olleH
ereh
t
Or if you added a character, e.g.
$ ./bin/revstr
Enter the width of an output line : 5
Enter your text : Hello Mickey
olleH
yekc
iM
Look things over and let me know if you have further questions.
Relax... take a deep breath... and think slowly about what's needed...
It is a standard 'beginner' notion that things are complicated and involve lots of variables and esoteric calculations. It takes a bit of experience to learn to pause-and-assess the problem BEFORE touching the keyboard.
Consider this:
int main() {
char input[ 120 + 1]; // some variables
int olen = 0;
// some user input
printf( "Width of an output line: " );
scanf( "%d", &olen );
/* omitting validation for brevity */
// more user input using "scanf()" parameters that work
printf( "Enter text: ");
if( scanf( " %120[^\n]", input ) != 1 ) {
fprintf( stderr, "scanf failed\n" );
return 1;
}
// Now, output from the "back end", while counting 'modulo' to insert line breaks.
int up = 1;
for( int i = strlen( input ) - 1; i >= 0; i-- ) {
putchar( input[ i ] );
if( up++ % olen == 0 ) // time for a 'line break' ?
putchar( '\n' );
}
// All done.
return 0;
}
Width of an output line: 5
Enter text: Hello there
ereht
olle
H
Width of an output line: 8
Enter text: Twas brillig and the slithy toves...
...sevot
.yhtils. // some '.' added in post processing for clarity.
eht dna.
gillirb.
sawT...
There's no need for a 2nd buffer, or for a lot of variables whose values you begin to lose track of... Just keep things simple!
An exercise is to modify the code above to reverse the string "in place", then output substrings of the right length on separate lines. Also, reverse each substring independently.

Print out the third word in a string. C

So I am trying to write a program that takes a sentence and prints it out from the third word. Ex one two three four should print out three four.
Now this code works but I have no idea why as the logic under the else statement make it seem like it should not.
Would be thankful if someone could explain why it works like this.
Here is the code:
#include <stdio.h>
#include <string.h>
#define SIZE 100
int main(void) {
char arr[SIZE];
char *point;
char again = 'n';
do {
int count = 0;
for (int i = 0; i < SIZE; i++) {
arr[i] = '\0';
}
printf("Enter a sentence:");
gets(arr);
for (int i = 0; i < SIZE; i++) {
if (arr[i] == ' ') {
count++;
}
}
if (count < 2) {
printf("The sentence is to short!\n");
} else {
count = 1; //shouldn't this be count = 0?
for (int i = 0; i < SIZE; i++) {
if (arr[i] == ' ') {
count++;
}
if (count == 2) {
point = &arr[i + 2]; //shouldn't this be [i+1]?
}
}
printf("%s\n", point);
}
printf("Do you want to try again? (y/n)");
scanf("%c", &again);
while (getchar() != '\n');
} while (again == 'y' || again == 'Y');
return 0;
}
Your code has multiple problems:
You should never use gets(). This function has been removed from the C Standard because it cannot be given the maximum number of characters to write to the destination buffer, so any sufficiently long line from the input stream will cause undefined behavior. This is a classic security flaw. Use fgets() instead.
The loop while (getchar() != '\n'); will cause an infinite loop if there is no newline before the end of file, which will happen if you redirect input an empty file. You should also check for EOF:
while ((c = getchar()) != EOF && c != '\n')
continue;
There is no need to initialize the destination array, but you should check if the input operation succeeded, by comparing the return value of fgets() to NULL.
When iterating through the array to count spaces, you should stop at the null terminator. The contents of the array beyond the null terminator is indeterminate after the input operation, even if you initialized it prior to the call.
The code to skip the words is cumbersome and not easy to validate. Indeed point = &arr[i+2]; should be point = &arr[i+1].
words might be separated by more than one space, and initial spaces should be ignored.
Here is a corrected version using string functions strspn and strcspn to skip blanks and non-blanks:
#include <stdio.h>
#include <string.h>
#define SIZE 100
#define WS " \t\n\r\v\f" /* white space characters */
int main(void) {
char arr[SIZE];
char *p;
for (;;) {
printf("Enter a sentence:");
if (fgets(arr, sizeof arr, stdin) == NULL)
break;
p = arr;
p += strspn(p, WS); /* skip initial spaces */
p += strcspn(p, WS); /* skip first word */
p += strspn(p, WS); /* skip spaces */
p += strcspn(p, WS); /* skip second word */
p += strspn(p, WS); /* skip spaces */
if (*p == '\0') {
printf("The sentence is too short!\n");
} else {
printf("%s", p);
}
printf("Do you want to try again? (y/n)");
if (fgets(arr, sizeof arr, stdin) == NULL)
break;
if (*arr != 'y' && *arr != 'Y')
break;
}
return 0;
}
Another simple way to handle the word count is to walk-a-pointer down your string in a state loop keeping track of whether you are in a word (if so increase word count), otherwise you are not in a word and just keep walking down the buffer (i.e. iterating over each char) until you find the next word (or end of string).
The logic is simple, after filling your buffer, and setting a pointer to it, e.g.
#define MAXC 1024 /* buffer size (don't skimp) */
#define NWORD 3 /* output beginning with NWORD word */
...
char buf[MAXC] = "", /* buffer to hold line */
*p = buf; /* pointer to walk down buffer */
int n = 0, /* word counter */
in = 0; /* flag - in a word */
Just loop checking each character with isspace() and handle setting your in flag to either 1 (in word) or 0 (in space before or between words) incrementing your counter each time you go in a new word, and exiting the loop when your count reaches 3, e.g.
for (; *p; p++) { /* loop over each char */
if (!in && !isspace(*p)) { /* if not in word and not space */
in = 1, n++; /* set in flag, increment words */
if (n == NWORD) /* if 3rd word, break */
break;
}
else if (isspace(*p)) /* if space */
in = 0; /* unset in flag */
}
Putting it altogether in a short example, you could do something similar to the following which takes input until the Enter key is pressed alone on an empty line, and outputting each sentence entered beginning with the third-word, or displaying the error "too few words." if a sentence with less that three words is entered, e.g.
#include <stdio.h>
#include <ctype.h>
#define MAXC 1024 /* buffer size (don't skimp) */
#define NWORD 3 /* output beginning with NWORD word */
int main (void) {
for (;;) { /* loop continually until empy-line */
char buf[MAXC] = "", /* buffer to hold line */
*p = buf; /* pointer to walk down buffer */
int n = 0, /* word counter */
in = 0; /* flag - in a word */
fputs ("\nenter sentence: ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin) || *buf == '\n') { /* read line */
puts ("all done!");
break;
}
for (; *p; p++) { /* loop over each char */
if (!in && !isspace(*p)) { /* if not in word and not space */
in = 1, n++; /* set in flag, increment words */
if (n == NWORD) /* if 3rd word, break */
break;
}
else if (isspace(*p)) /* if space */
in = 0; /* unset in flag */
}
if (n == NWORD) /* if 3 or more words */
fputs (p, stdout);
else /* other wise handle error */
fputs ("too few words.\n", stderr);
}
return 0;
}
Example Use/Output
$ ./bin/thirdword
enter sentence: one two three four five
three four five
enter sentence: one two
too few words.
enter sentence: one two three
three
enter sentence:
all done!
Look things over and let me know if you have further questions.
count = 1; //shouldn't this be count = 0? and point = &arr[i + 2]; //shouldn't this be [i+1]?
The following answers both questions.
count count count count
0 1 2 3
one two three four
i+0 i+1 i+2 i+3
point = &arr[i + 2]; along with printf("%s\n", point); says that print all characters from address of arr[i + 2] till seeing \0 character

Random Characters Appearing When Printing Arrays

I'm relatively new to coding array functions in C. After numerous tries, I've decided to surrender and ask for help.
I wish to the user to input the words and store them into the 2d array words. The problem is that it prints the words but also prints out random characters.
#include "mp1_lib.h"
void get_words(int n, char words[][16])
{
char c = ' ';
char check;
for(int x=0; x <= n; x++)
{
for(int y=0; y < 16; y++)
{
c = getchar();
check = c;
if (check == '\n')
{
break;
}
words[x][y] = c;
}
}
}
void print_words(int n, char words[][16])
{
for(int x=1; x <= n; x++)
{
for(int y=0; y < 16; y++)
{
if (words[x][y] == '\n')
{
break;
}
putchar(words[x][y]);
}
printf("\n");
}
}
In C, a string is an array of characters with the nul-terminating character '\0' as the character that marks the end of the contents of the string within the array. That is how all string functions like strlen or printf using the '%s' format specifier to print a string -- know where the string stops.
If you do not nul-terminate the array of characters -- then it is not a string, it is simply an array and you cannot pass an un-terminate array to any function expecting a string - or it won't know where the string ends (and in the case of printf will just print whatever unspecified character happens to be in memory until it comes upon a '\0' to stop the output (or SegFaults).
If you don't nul-terminate the words in your array, then you will have to have some way to store the number of characters in each word, so your print function will know where to stop printing. (if you have a two-letter word like "Hi" in a 16-char array, you can only print 2 characters from the array. Especially if it is an uninitialized array, then you will simply get gibberish printed for characters 3-16.
Your second problem is -- "How do you know how many words you have stored in your array?" -- you don't return a value from getwords, so unless you change the function type to int and return the number of words that you stored in your array, your only other option is to pass a pointer to an integer and update the value at that address so the value is available back in the calling function. Either way is fine, you generally only worry about making a value available through a pointer if you are already returning another value and need a second method to make another updated value visible back in the calling function (main() here).
Putting those pieces together, and passing a pointer to the number of words to getwords to make the number of words entered available back in main() (so you know how many words print_words has to print), you could do something similar to the following:
#include <stdio.h>
#include <ctype.h>
#define MAXC 16 /* if you need constants, define them */
#define MAXW 32
void getwords (char (*words)[MAXC], int *n)
{
int col = 0; /* column count */
while (*n < MAXW) { /* while words < MAXW */
int c = getchar(); /* read char */
/* column reaches MAXC-1 or if whitespace or EOF */
if (col == MAXC - 1 || isspace(c) || c == EOF) {
if (col) { /* if col > 0 */
words[(*n)++][col] = 0; /* nul-terminate, increment n */
col = 0; /* set col to zero */
}
if (c == EOF) /* if char EOF - all done */
return;
}
else /* otherwise - just add char to word */
words[*n][col++] = c;
}
}
void prnwords (char (*words)[MAXC], int n)
{
for (int i = 0; i < n; i++) /* loop over each of n-words & print */
printf ("words[%2d]: %s\n", i, words[i]);
}
int main (void) {
char words[MAXW][MAXC] = {""}; /* intiliaze words all zero */
int nwords = 0; /* number of words zero */
getwords (words, &nwords);
prnwords (words, nwords);
return 0;
}
(note: when reading characters into the words array, you must check the number of character read again the maximum characters per-word (MAXC) and the number of words against the maximum number of words/rows in your array (MAXW) to prevent writing outside of your array bounds -- which will invoke Undefined Behavior in your program)
(note: the ctype.h header was included to simplify checking whether the character read was whitespace (e.g. a space, tab, or newline). If you can't use it, then simply use an if (c == ' ' || c == '\t' || c == '\n') instead.)
Example Use/Output
$ echo "my dog has fleas and my cat has none" | ./bin/getwords
words[ 0]: my
words[ 1]: dog
words[ 2]: has
words[ 3]: fleas
words[ 4]: and
words[ 5]: my
words[ 6]: cat
words[ 7]: has
words[ 8]: none
Not too familiar with c. But it appears like you are not addding the new line character to the words array in get_words.
check = c;
if (check == '\n')
{
break;
}
words[x][y] = c;
So when printing in print_words this will never be true.
if (words[x][y] == '\n')
{
break;
}
That means that whatever happens to be in the memory location is what will get printed.
Your words have neither the newline character (which makes your code print garbage) nor the terminating NULLs (which makes them illegal as C strings). At least add words[x][y]="\n" before breaking the inner loop. Or, rather, move the if check after the assignment words[x][y]=c;. And yes, the loop should go from 0 to n-1.
As a side note, you do not need the variable check: just use c.
I tried to assign space as a placeholder for the 15 characters and it worked. Thanks, everyone! :)
#include "mp1_lib.h"
void get_words(int n, char words[][16])
{
char c = ' ';
char check;
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
words[x][y] = ' ';
}
}
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
c = getchar();
check = c;
if (check == '\n')
{
break;
}
words[x][y] = c;
}
}
}
void print_words(int n, char words[][16])
{
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
putchar(words[x][y]);
}
printf("\n");
}
}

I want to read from text file that displays which character appears most or least often (keyboard or text file) ? :)

Here's my code:
include <stdio.h>
int main()
{
char str[1000], ch;
int i, frequency = 0;
printf("Enter a string: ");
gets(str);
printf("Enter a character to find the frequency: ");
scanf("%c",&ch);
for(i = 0; str[i] != '\0'; ++i)
{
if(ch == str[i])
++frequency;
}
printf("Frequency of %c = %d", ch, frequency);
return 0;
I figured that the frequency of characters code I came up with is similar. How to implement the character which appears more / less often in standard input or text file?
Also, should I use StreamReader sr = new StreamReader("example.txt") for reading normal text files for this code?
EDIT: Have to use Switch /M for most often and /L for least often.
That's a good start...
include <stdio.h>
int main()
{
char str[1000], ch,lookup_Chars[256];
int i, frequency = 0;
char counter;
printf("Enter a string: ");
gets(str);
printf("Enter a character to find the frequency: ");
scanf("%c",&ch);
for(i = 0; str[i] != '\0'; ++i)
{
lookup_Chars[str[i]]++;
}
for(counter = 0; counter<sizeof(lookup_Chars); counter++)
{
printf("Frequency of %c = %d", counter, lookup_Chars[counter]);
}
return 0;
Never, never, never use gets. It is so insecure and so susceptible to buffer overrun, it has been removed from the C standard library. Use fgets instead, just be aware that fgets will read and include the trailing '\n' in the buffer it fills (just as all legitimate line oriented input functions do, such as POSIX getline). This prevents leaving a '\n' unread in the input buffer (e.g. stdin) following each user input.
You risk Undefined Behavior because you do not validate the contents of str in any way and then you fail to validate the return of scanf to insure a character was read. (the user could cancel input in either case by generating an EOF with Ctrl+d on *nix systems of with Ctrl+z on windoze).
Further, you must understand that scanf will leave characters in the input buffer (as will fgets if the line is longer than the amount of storage you have allocated). That is one of the most common pitfalls new C programmers fall victim to. (failing to validate a complete line of input was read and failing to handle characters that remain in the input buffer)
When taking user input with fgets (which is recommended), since it reads and includes the '\n' in the buffer it fills, you simply check the length of the buffer read with strlen and then make sure the last character is a '\n'.
scanf is full of pitfalls when used for user input. While it can be used, if used correctly with it's return validated and any remaining characters emptied from stdin before your next call to scanf, you have to approach it use that way. In your case ch is the last input for your file, but try taking input for ch before reading the string and see what happens...
Putting it altogether, and adding validations for both str and ch, and adding additional comments in-line below, you could do something similar to the following:
#include <stdio.h>
#include <string.h>
#define MAXS 1024 /* if you need a constant, define one */
int main (void) {
int frequency = 0;
char str[MAXS] = "",
*p = str, /* pointer to str */
ch;
printf ("Enter a string: ");
if (fgets (str, MAXS, stdin)) { /* validate input received */
size_t len = strlen (str); /* get length of str */
if (len && str[len - 1] != '\n') { /* validate all input read */
fprintf (stderr, "error: line exceeds %d chars.\n", MAXS-2);
return 1;
}
}
else { /* if fgets failed - user generated EOF to cancel */
fprintf (stderr, "error: user canceled input (EOF).\n");
return 1;
}
printf ("Enter a character to find the frequency: ");
if (scanf ("%c", &ch) != 1) { /* note: chars will remain in stdin */
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
while (*p != '\n') /* just use a pointer to str */
if (*p++ == ch) /* compare to ch and increment to next char */
frequency++; /* increment frequency if they are equal */
printf ("\nFrequency of %c = %d\n", ch, frequency);
return 0;
}
(note: you could declare char ch[3] = ""; and use fgets to read fgets (ch, sizeof ch, stdin) and then simply compare if (*p++ == *ch) to prevent leaving the '\n' in stdin (but you would still need to validate that it was the final character read, and if not manually empty stdin))
Exammple Use/Output
$ ./bin/freqofc
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: a
Frequency of a = 10
$ ./bin/freqofc
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: p
Frequency of p = 2
$ ./bin/freqofc
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: z
Frequency of z = 0
Look things over, think about the validations that were made, and let me know if you have any further questions.
Using a Frequency Array to Capture Count of all Chars
Using a frequency array allows you to capture the frequency of all characters (or the independent count of any element of a set). Essentially, you use an array initialized to zero with one element for each member of the set you want to count the frequency of each occurrence. Since there are 128 ASCII Characters, you can simply use an array of 128 elements, e.g. int frequency[128] = {0};.
If you look at the link provided, you see the ASCII value of each character corresponds to a value between 0-127, so when looping over each character in the input string, if you increment the array index that corresponds to the character, you end up with the total count for each character in its corresponding element. For example, if p is a pointer to the beginning of str, then you can loop over each character in the string capturing their frequency in the frequency[*p] element of the array:
while (*p != '\n') {
frequency[*p]++; /* increments element corresponding to char *p */
p++; /* note: cast to (int)*p intentional omitted */
}
Now that you have the frequency for every character stored in the frequency, you can simply loop over the elements you are concerned about to determine max/min, etc... Note: the normal printable characters begin with 'space' (ASCII 32, or hex 0x20) and end with '~' (ASCII 126 or hex 0x7e`). So just limit your check of values to the printable range, e.g.
/* loop over printable characters (see ASCII Chart), for max/min */
for (int i = ' '; i <= '~'; i++) {
/* require a frequency of at least 1 for min */
if (frequency[i] && frequency[i] < min) {
min = frequency[i]; /* save least frequent count */
minc = i; /* save least frequent char */
}
if (frequency[i] > max) { /* just find max */
max = frequency[i]; /* save same for max */
maxc = i;
}
}
(note: you can further micro-divide ranges for only lowercase, uppercase, digits, etc..)
Putting that altogether, you can do something similar to the following to report the number of occurrence if the wanted char, the max occurring char, the min occurring char (and then summarize by dumping the frequency of all chars):
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAXS 1024 /* if you need a constant, define one */
#define NASCII 128 /* number of ASCII chars (includes non-printing) */
int main (void) {
int frequency[NASCII] = {0},
max = INT_MIN,
min = INT_MAX;
char str[MAXS] = "",
*p = str, /* pointer to str */
ch,
minc = 0,
maxc = 0;
printf ("Enter a string: ");
if (fgets (str, MAXS, stdin)) { /* validate input received */
size_t len = strlen (str); /* get length of str */
if (len && str[len - 1] != '\n') { /* validate all input read */
fprintf (stderr, "error: line exceeds %d chars.\n", MAXS-2);
return 1;
}
}
else { /* if fgets failed - user generated EOF to cancel */
fprintf (stderr, "error: user canceled input (EOF).\n");
return 1;
}
printf ("Enter a character to find the frequency: ");
if (scanf ("%c", &ch) != 1) { /* note: chars will remain in stdin */
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
while (*p != '\n') /* just use a pointer to str */
frequency[(int)*p++]++; /* increment element representing ch */
/* loop over printable characters (see ASCII Chart), for max/min */
for (int i = ' '; i <= '~'; i++) {
/* require a frequency of at least 1 for min */
if (frequency[i] && frequency[i] < min) {
min = frequency[i]; /* save least frequent count */
minc = i; /* save least frequent char */
}
if (frequency[i] > max) { /* just find max */
max = frequency[i]; /* save same for max */
maxc = i;
}
}
/* ouput requested char freq, and max/min chars */
printf ("\nFrequency of %c = %d\n"
"least frequent occurrence: %c = %d\n"
" most frequent occurrence: %c = %d\n\n",
ch, frequency[(int)ch], minc, min, maxc, max);
/* output frequency of all printable chars */
printf ("frequency of all printable characters:\n");
for (int i = ' '; i < '~'; i++)
if (frequency[i])
printf (" '%c' : %d\n", i, frequency[i]);
return 0;
}
Exammple Use/Output
$ ./bin/freqofc2
Enter a string: a man a plan a canal panama
Enter a character to find the frequency: m
Frequency of m = 2
least frequent occurrence: c = 1
most frequent occurrence: a = 10
frequency of all printable characters:
' ' : 6
'a' : 10
'c' : 1
'l' : 2
'm' : 2
'n' : 4
'p' : 2
Adding /L or /M Switches for Least/Max Occurrences
To add command line switches, for a minimum number in a known order, you can simply use the allowable argument count and argument vector parameters to main(), e.g. int main (int argc, char **argv). Example:
int main (int argc, char **argv) {
...
/* validate "/L" or "/M" provided as an argument */
if (argc != 2 || (argv[1][1] != 'L' && argv[1][1] != 'M')) {
fprintf (stderr, "error: insufficient input, req'd /M or /L.\n");
return 1;
}
To test and output either the least or minimum, you simply test which character is present and act accordingly, e.g.
...
if (argv[1][1] == 'L') /* output requested lease or max */
printf ("requested least frequent occurrence: %c = %d\n\n",
minc, min);
else
printf ("requested most frequent occurrence: %c = %d\n\n",
maxc, max);
Putting that together an a complete example would be:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAXS 1024 /* if you need a constant, define one */
#define NASCII 128 /* number of ASCII chars (includes non-printing) */
int main (int argc, char **argv) {
int frequency[NASCII] = {0},
max = INT_MIN,
min = INT_MAX;
char str[MAXS] = "",
*p = str, /* pointer to str */
ch,
minc = 0,
maxc = 0;
/* validate "/L" or "/M" provided as an argument */
if (argc != 2 || (argv[1][1] != 'L' && argv[1][1] != 'M')) {
fprintf (stderr, "error: insufficient input, req'd /M or /L.\n");
return 1;
}
printf ("Enter a string: ");
if (fgets (str, MAXS, stdin)) { /* validate input received */
size_t len = strlen (str); /* get length of str */
if (len && str[len - 1] != '\n') { /* validate all input read */
fprintf (stderr, "error: line exceeds %d chars.\n", MAXS-2);
return 1;
}
}
else { /* if fgets failed - user generated EOF to cancel */
fprintf (stderr, "error: user canceled input (EOF).\n");
return 1;
}
printf ("Enter a character to find the frequency: ");
if (scanf ("%c", &ch) != 1) { /* note: chars will remain in stdin */
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
while (*p != '\n') /* just use a pointer to str */
frequency[(int)*p++]++; /* increment element representing ch */
/* loop over printable characters (see ASCII Chart), for max/min */
for (int i = ' '; i <= '~'; i++) {
/* require a frequency of at least 1 for min */
if (frequency[i] && frequency[i] < min) {
min = frequency[i];
minc = i;
}
if (frequency[i] > max) { /* just find max */
max = frequency[i];
maxc = i;
}
}
/* ouput requested char freq, and max/min chars */
printf ("\nFrequency of %c = %d\n"
"least frequent occurrence: %c = %d\n"
" most frequent occurrence: %c = %d\n\n",
ch, frequency[(int)ch], minc, min, maxc, max);
if (argv[1][1] == 'L') /* output requested lease or max */
printf ("requested least frequent occurrence: %c = %d\n\n",
minc, min);
else
printf ("requested most frequent occurrence: %c = %d\n\n",
maxc, max);
/* output frequency of all printable chars */
printf ("frequency of all printable characters:\n");
for (int i = ' '; i < '~'; i++)
if (frequency[i])
printf (" '%c' : %d\n", i, frequency[i]);
return 0;
}
Let me know if you have any questions.

array reverse output in c

I do this program which receives input from a string and a substring, and then searches for the substring within the string by determining how often it appears (the number of occurrences) and the locations it is located, then these positions are inserted into an array for example (4 5 8) And they are printed correctly, now what I was trying to do, once I got my array with inside the locations where the substring was found it print it in reverse ie (8 5 4) I tried using this cycle
// reverse output
printf ("%d", count);
for (j = count - 1; j >= 0; j--)
    printf("%d", pos[j]);
But if the array positions are 8 5 4 so it prints to me
5 ,4, -311228772
Why does this happen? Here is the code:
// inclusion of libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
 Reads a string allocated by the stream.
 It stops at newline, not included in string.
 Returns NULL to EOF
 */
char *my_getline(FILE *stream) { // statement of function
char *line = NULL; // this is just the pointer initialization
size_t pos = 0; // definition of position variables and init
int c; // a variable to store the temporary character
while ((c = getc(stream)) != EOF) // read every character until the end of the file
{
     char *newp = realloc(line, pos + 2); // To dynamically allocate memory, with reference to the number of characters and more '2' is only to compensate for the null character and the character (since it is 0)
     if (newp == NULL) { // checks whether memory has been properly associated or not.
         free(line); // if the line is not free the blank
         return NULL; // interrupts the program and returns NULL
     }
     line = newp; // if memory is allocated correctly stores the memory allocated to the line pointer
     if (c == '\n') // if a new line is detected
         break; // interrupts the while cycle
     line[pos++] = (char)c; // stores the character in dynamic memory and the new character in the new location.
}
if (line) { // if the line contains something then a null character is added at the end to complete that string.
    line[pos] = '\0';
}
return line; // returns the contents of the line.
}
int main(void) { // main statement
    char *str, *sub; // character punctuation statement
    size_t len1, len2, i, count = 0; // unsigned value statement "size_t is equal to unsigned int" so may also be <0
    int pos[count]; // declare a count array to insert the index then print it in reverse
int j;
// Here is the main string
    printf("Enter Main String: \n"); // print the entry and enter the main string
    str = my_getline(stdin); // inserts the entered string inside the pointer using my_getline function and using getchar analogue stdin to make the entered characters input from the standard input
    // here is the substring to look for
    printf("Enter substring to search: \ n"); // print the entry and enter the main substring
    sub = my_getline(stdin); // inserts the entered string inside the pointer using my_getline function and using getchar analogue stdin to make the entered characters input from the standard input
    if (str && sub) { // if string and substring && = and
        len1 = strlen(str); // inserts the string length in the len1 variable
        len2 = strlen(sub); // inserts the length of the string in the len2 variable
        for (i = 0; i + len2 <= len1; i++) { // loop for with the control that the substring is less than or equal to the main string ie len2 <= len1
            if (! memcmp(str + i, sub, len2)) { // here uses the memcmp function to compare the string and substring byte bytes
                count++; // count variable that is incremented each time the sub is found in p
                // here is where it gets in output
// If the substring was found mold the index with the locations it was found
pos[count] = i + 1;
printf( "%d\n", pos[count]);
            }
        }
// print to get reverse output
printf("number of times%d", count);
// print to get reverse output
printf("%d", count);
       for (j = count - 1; j >= 0; j--)
       printf("%d", pos[j]);
 
        if (count == 0) { // if count is = 0 ie the substring was not found string string not found
            // otherwise if not found
            printf("Subtry not found \n");
        }
    }
// free releases the memory area that was reserved for the string and substrings so that it can be reused in the next run
    free(str);
    free(sub);
    return 0; // exit analog
}
Your code is completely unreadable. Even reformatted and spaced out, the comments make it difficult to see the important stuff.
You should only comment the non obvious: int main(void) {// main statement is a good example of a useless counter productive comment.
After removing all comments, the code shows a few problems:
There is an extra space in printf("Enter substring to search: \ n");
The array pos is defined with a size of 0: int count = 0; int pos[count];. The program has undefined behavior.
count is incremented before storing the offset into the array. Hence the array contents does not start at index 0, hence producing incorrect output when you iterate from count-1 down to 0 in the second loop.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Reads a string from the stream allocated with malloc
stops at newline, not included in string.
Returns NULL at EOF
*/
char *my_getline(FILE *stream) {
char *line = NULL;
size_t pos = 0;
int c;
while ((c = getc(stream)) != EOF) {
char *newp = realloc(line, pos + 2);
if (newp == NULL) {
free(line);
return NULL;
}
line = newp;
if (c == '\n')
break;
line[pos++] = (char)c;
}
if (line) {
line[pos] = '\0';
}
return line;
}
int main(void) {
printf("Enter Main String:\n");
char *str = my_getline(stdin);
printf("Enter substring to search:\n");
char *sub = my_getline(stdin);
if (str && sub) {
size_t count = 0;
size_t len1 = strlen(str);
size_t len2 = strlen(sub);
size_t pos[len1 + 1];
for (size_t i = 0; i + len2 <= len1; i++) {
if (!memcmp(str + i, sub, len2)) {
pos[count] = i + 1;
printf("%d\n", (int)pos[count]);
count++;
}
}
if (count != 0) {
printf("number of times: %d\n", (int)count);
for (size_t j = count; j-- > 0;) {
printf(" %d", (int)pos[j]);
}
printf("\n");
} else {
printf("substring not found.\n");
}
}
free(str);
free(sub);
return 0;
}
You declared pos as an array of length 0:
size_t ... count = 0;
int pos [count];
Thus, inside your for-loop you'll access some unitialized memory:
for (j = count-1; j>= 0; j--)
printf ("%d", pos [j]);

Resources