Why is it showing random numbers? C program to read string letters - c

So I have to create a program that reads the user input and shows how many times each letter appears in that string, and also how many non-letters but my code for alphabets is showing random numbers..
#include <stdio.h>
#include <string.h>
#define SIZE 100
void readInput (char string[]);
void Calc(char string[], int letters[]);
void
readInput (char string[])
{
printf ("Enter a String:\n");
fgets (string, SIZE, stdin);
string[strlen (string) - 1] = '\0';
}
void
Calc(char string[], int letters[])
{
int c = 0, x;
while (string[c] != '\0')
{
if (string[c] >= 'a' && string[c] <= 'z')
{
x = string[c] - 'a';
letters[x]++;
}
c++;
}
for (c = 0; c < 26; c++)
printf ("%c occurs %d times in the entered string.\n", c + 'a', letters[c]);
}
int
main ()
{
char string[SIZE];
int letters[26];
readInput (string);
Calc(string, letters);
return 0;
}
This is the output
I'm new to strings I've googled examples but can't seem to find whats wrong with my code and no idea how I will include the non-letters part.

The contents of letters are not initialised. Formally the behaviour of your program is indeterminate.
Sort that by writing int letters[26] = {0}; Doing that sets all elements to zero, which is what you want in this case.

letters[] is uniinitialized.
Solution int letters[26]={0}.
You are reading an uninitialized value which is indeterminate. And the results doesn't conform to as you expect it to be.
Here you want to initialize the elements with 0 denoting that you haven't seen any charcaters yet. (automatic storage duration).
A better way to overwrite the '\n' would be
string[strcspn(string, "\n")] = 0;

you should initialize letters with all 0 values

Related

My main function does not allow me to enter any input and crashes after a while

Basically the program is supposed to allow me to test the words . I am trying learn how to add multiple functions inside the main function but for some reason , I couldn't run the program . Could I know where is my mistake or how can I work on the program .
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
void read_word(int counts[26]);
bool equal_array(int counts1[26] , int counts2[26]);
int main (void)
{
int counts1[26] = {0} , counts2[26] = {0} ;
read_word(counts1);
read_word(counts2);
if(equal_array(counts1, counts2)){
printf("The words are not anagrams");
}
else{
printf("The words are anagrams");
}
return 0;
}
void read_word(int counts[26])
{
char ch , alphabet ;
printf("Enter word: ");
//initialise the letters array first and assign all of them value of 0
for(alphabet = 'a' ; alphabet <= 'z'; alphabet++){
counts[alphabet] = 0;
}
//first loop to get the word and num
while ((ch = getchar()) != '\n')
{
if (isalpha(ch))
{
counts[tolower(ch)]++;
}
counts[ch]++; //Is this statement needed ? why ?
}
}
bool equal_array(int counts1[26] , int counts2[26])
{
char alphabet;
//third loop to check the whole array
for (alphabet = 'a' ; alphabet <= 'z'; alphabet++)
{
if (counts1[alphabet] != counts2[alphabet])
{
return true ;
}
else
{
return false;
}
}
}
As mentioned above in the comment, the ASCII value for 'a' is 97 and 122 for 'z'. When you attempt to iterate:
for(alphabet = 'a' ; alphabet <= 'z'; alphabet++){
counts[alphabet] = 0;
}
You access elements well beyond the end of your array -- invoking Undefined Behavior. See ASCII Table & Description. The irony (as also mentioned in the comment) is the loop is entirely unnecessary because your declaration and initialization of your arrays already set each element in the arrays to zero:
int counts1[26] = {0} , counts2[26] = {0};
While not an error, passing the arrays as, e.g. void read_word(int counts[26]);, shows a misconception of how arrays are treated on access. On access, an array is converted to a pointer to its first elements. This is known as Array / Pointer Conversion and it is set forth in the standard at C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). What this means is you simply need to provide a pointer as the parameter to represent your arrays in the function arguments, e.g.
void read_word (int *counts);
bool equal_array (int *counts1, int *counts2);
Don't Hardcode Filenames or Use Magic Numbers in Your Code
When you write code, you don't want to sprinkle Magic Numbers (e.g. 26) or hardcode filenames. Instead, if you need a constant, #define one or use a global enum for the same purpose:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#define ALPHA 26 /* if you need a constant, #define one (or more) */
...
int main (void)
{
int counts1[ALPHA] = {0},
counts2[ALPHA] = {0};
Why? If you need to make changes later to the value, you don't have to go picking through each array declaration or loop limit to make changes. You have one single convenient location up top to make the change and it is automatically applied throughout your code.
If you need to pass a filename to your program, pass it as an argument to main() (that's what int argc, char **argv are for) or take input from the user. Why? You shouldn't have to recompile your program just to read from a different filename.
Match Your Variable Type to Function Return Type
Declaring char ch; and then assigning ch = getchar(); is not right. Why? What is the declaration for getchar()? See man 3 getchar. How is it declared and what does it return?
int getchar(void);
The function returns int not char, so you must declare int ch; instead of char ch;. It also allows you to validly check if (ch == EOF).
Your read_word() Function
When you are reading with getchar(), in addition to checking for '\n', you must also check for EOF. There is no guarantee your line will end with '\n'. The user may very well generate a manual EOF with Ctrl + d (or Ctrl + z on windows). Therefore your loop should be:
void read_word (int *counts)
{
int ch; /* ch must be int to match getchar() and catch EOF */
fputs ("Enter word: ", stdout);
while ((ch = getchar()) != '\n' && ch != EOF) /* loop over each char in line */
{
if (isalpha(ch))
{
counts[tolower(ch) - 'a']++; /* map to zero-based index */
}
// counts[ch]++; //Is this statement needed ? why ?
// no - only alpha chars are counted
}
}
Note: tolower() returns lower-case character (e.g. the ASCII value for the lower-case character). Therefore to map the character back to your Zero-Based array index, you must subtract 'a' from the return.
Give Your Functions Names With Plain Meaning
Your equal_array() function returns true if the arrays counts1 and counts2 are NOT equal and returns false if the ARE equal. That is directly opposite of what equal_arrays means. Instead, you could do:
bool equal_array (int *counts1, int *counts2)
{
for (int i = 0; i < ALPHA; i++)
if (counts1[i] != counts2[i])
return false;
return true;
}
(note: there is never the need for an else if all that happens is a return)
Putting it altogether you would have:
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#define ALPHA 26 /* if you need a constant, #define one (or more) */
void read_word (int *counts);
bool equal_array (int *counts1, int *counts2);
int main (void)
{
int counts1[ALPHA] = {0},
counts2[ALPHA] = {0};
read_word(counts1);
read_word(counts2);
if (equal_array(counts1, counts2))
puts ("The words are anagrams");
else
puts ("The words are not anagrams");
return 0;
}
void read_word (int *counts)
{
int ch; /* ch must be int to match getchar() and catch EOF */
fputs ("Enter word: ", stdout);
while ((ch = getchar()) != '\n' && ch != EOF) /* loop over each char in line */
{
if (isalpha(ch))
{
counts[tolower(ch) - 'a']++; /* map to zero-based index */
}
// counts[ch]++; //Is this statement needed ? why ?
// no - only alpha chars are counted
}
}
bool equal_array (int *counts1, int *counts2)
{
for (int i = 0; i < ALPHA; i++)
if (counts1[i] != counts2[i])
return false;
return true;
}
Example Use/Output
$ ./bin/isanagram
Enter word: anagram
Enter word: nag a ram
The words are anagrams
or
$ ./bin/isanagram
Enter word: anagram
Enter word: nag a ham
The words are not anagrams
Now it is working as it should. Let me know if you have any further questions.

C programming. Function to generate a string of random letters using only arrays and then pointers

Im trying to code a program in C to generate a string containing random letters using only arrays first and then again using pointers. I've looked at many other questions but is not quite what I'm trying to accomplish. I can really use help please.
Function 1- Generates a string with random upper
case letter A-Z with 40 characters.
Function 2- Function to let user enter a string
with random upper case letter and a replacement character.
Function 3- Searches string1 from function 1 and replaces
occurences of any character from string 2 (user entered) with
replacement character.
OUTPUT EX.
String 1- "AABBCCDDEEFFGGHHABCDEFGH"
String 2- "BE"
Replacement char- "3"
Filtered string- AA33CCDD33FFGGHHA3CD3FGH.
This is what I have so far, Im not very good with arrays.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int s1 [41];
srand(time(NULL));
int i;
for (i = 0; i < 41; i++)
{
s1 [i] = rand();
}
return 0;
}
Any help will be appreciated.
Thanks alot.
#include <stdio.h>
#include <stdlib.h>
void rand_str(char* txt, size_t sz)
{
int i=sz-1;
while( i --> 0 )
{
txt[i] = 'A' + rand() % 26;
}
printf("Random Str: %.*s\n", sz+i, txt);
}
void fn2(char* tgt, size_t sz, char* repl )
{
puts("String 2: ");
fgets(tgt, sz, stdin);
puts("Replacement Char: ");
*repl = getchar();
}
void search_replace(char* txt, char* tgt, char repl)
{
while(*tgt != '\0')
{
while ((strchr(txt, *tgt) ? (tgt[strchr(txt, *tgt)-tgt] = repl) : 0) == repl);
tgt++;
}
}
int main(void)
{
char txt[41] = {0};
char tgt[40] = {0};
char repl;
rand_str(txt, sizeof(txt));
fn2(tgt, sizeof(tgt), &repl);
search_replace(txt, tgt, repl);
return !printf("Filtered String: %s\n", txt);
}
Please note that I did not compile any of this code. It might have some typo and/or runtime errors. The concept is correct though and you should understand the code first and not just copy it.
Function 1:
#include <stdlib.h> // Important! rand() function that generate random function is in that library!
//This function returns a pointer of an array (arr). In other words it returns the **address** of the first character of the array.
// Assuming arr is valid!
char* randomString(char* arr){
// This part does not REALLLYY matters it just makes sure the random will truly be random...
time_t t;
srand((unsigned) time(&t)); // Seeds the random function.
//------------------
//Looping the array assigning random letters:
int i = 0;
while(i<SIZE){
arr[i] = 'A'+(rand()%('Z'-'A'+1));// 'A' has a numerical value, we want the range from 'A' to 'Z' to be random. 'Z'-'A' is the range of letters (26) because its a modulu if the modulu was just 'Z'-'A' (26) it wouldnt print Z. 'Z' is the 26th letter, 26%26 is zero, it will not give 'Z' this is why I increased 'Z'-'A' by 1 so the modulu will include 'Z' as random latter.
i = i + 1;
}
arr[i] = 0;// String terminator also called NULL.
return "lol";
}
Function 2:
#include <string.h>
int replace(char* inputString, char* userInput,char replacement ){
/* e.g.
inputString = "ABSDSADASBBBAA";//Generate yourself... (Might want to user function 1)
userInput = "AB"; // You need to do the user input yourself...
replacement = 'D';
*/
int i = 0;
while(i<strlen(inputString)){
int j = 0;
while(j<strlen(userInput)){
if(inputString[i]==userInput[j]){
inputString[i] = replacement;
}
j = j+1;
}
i = i + 1;
}
}
Function 3:
int main(){
// Just use regular IO libraries to get user's input...
// Assuming you did that, I will hard code the values (you need to do the IO e.g. gets())
char str[SIZE];
randomString(str); // Requirement #1 reuse of function 1
char * userInput = "AB"; // You need to do the user input yourself...
char replacement = 'D';// You need to do the user input yourself...
replace(str, userInput, replacement)//Requirement #2
return 0;
}

I want to count frequency or occurrence of a every letter in a string C program

Suppose if I pass a string like "I am Programmer".
If a letter has occurred one time it should print "I has occurred 1 time", or else if a letter appears twice in the string it should print "a has occurred 2 times", "m has occurred 3 times" and so on for every letter in the string. I searched it and found in some website. Is there any way we could rewrite the code because I didn't understand the code.
#include <stdio.h>
#include <string.h>
int main()
{
char string[100];
int c = 0, count[26] = {0};
printf("Enter a string\n");
gets(string);
while (string[c] != '\0')
{
/** Considering characters from 'a' to 'z' only
and ignoring others */
if (string[c] >= 'a' && string[c] <= 'z')
count[string[c]-'a']++;
c++;
}
for (c = 0; c < 26; c++)
{
/** Printing only those characters
whose count is at least 1 */
if (count[c] != 0)
printf("%c occurs %d times in the entered string.\n",c+'a',count[c]);
}
return 0;
}
Ok here is the rewrite, the original code is better but this one might be easier to understand:
#include <stdio.h>
#include <string.h>
int main()
{
char cur_char;
char string[100];
int index = 0, count[255] = {0};
printf("Enter a string\n");
gets(string);
while (string[index] != '\0')
{
char cur_char = string[index];
// cur_char is a char but it acts as the index of the array like
// if it was an unsigned short
count[cur_char] = count[cur_char] + 1;
index++;
}
for (index = 0; index < 255; index++)
{
if (count[index] != 0)
printf("%c occurs %d times in the entered string.\n", index, count[index]);
}
return 0;
}
A variable type char can be considered as an integer (it's how they are stored in the memory anyway) so you can write:
int test = 'a';
printf("%i", test);
And it will print you 97. Also letters from a to z are represented by continuous intergers, that means 'b' = 98. So taht also means 'b' - 'a' = 1
In your solution, they create an array of 26 integers to count the occurence of each letters betwin 'a' and 'z' (note that they ignore all others including A-Z by doing this)
They decided that in the array count, index 0 is here to count occurences of a, 1 for b .... 25 for z, that explains this:
count[string[c]-'a']++;
If string[c] is a b then string[c]-'a' = 1 so we have our index for count array and increase the amount of occurence of b.
So all you need to understand this code is that you can manipulate a char like an int basically, you should make a quick search about what is ASCII code as well.
If you still need a rewrite of this code to understand, tell me.

String comparison function

I am new to C and am trying to figure out and learn why my code isn't working. I understand that in C a string is basically an Array of each character. So I have been trying to search through the array to find the letter a and then print something if it is found. But my program keeps crashing every time I try to run it.
Here is my code:
#include <stdio.h>
void Display(char ch[]);
int main() {
char c[50];
printf("Enter String: ");
gets(c);
Display(c);
return 0;
}
void Display(char ch[]) {
int i;
for (i = 0; i < (sizeof(ch)); i++) {
if (strcmp(ch[i],"a") == 0) {
printf( "Yes");
}
}
}
When I run my program I enter a random string for example "fdas" and press enter. Then it crashes =\
Please remember I am new to C. I am a Java programmer if that helps with any explanations.
This is wrong
if(strcmp(ch[i],"a") == 0)
it should be
if (ch[i] == 'a')
and also, sizeof(ch) is not giving you the length of the string, for that you need strlen(), your Display() function should look like this to work
void Display(char *ch) {
size_t i;
size_t length;
if (ch == NULL)
return;
length = strlen(ch);
for (i = 0 ; i < length ; i++) {
if (ch[i] == 'a') {
printf( "Yes");
}
}
}
also, using gets() is unsafe, and deprecated, usefgets()
fgets(c, sizeof(c), stdin);
is better than gets(c) because it will prevent buffer overflow, note that I've used the sizeof operator in this case, because c is an array of char and the sizeof operator will give it's size in bytes, and since 1 char == 1 byte then it works.
In the case of the Display() function, it's not the same because there the sizeof operator will give the size of the type of ch, and since what you really need is the count of characters that ch points to, so you must use strlen() or compute the length yourself.

C program, Reversing an array

I am writing C program that reads input from the standard input a line of characters.Then output the line of characters in reverse order.
it doesn't print reversed array, instead it prints the regular array.
Can anyone help me?
What am I doing wrong?
main()
{
int count;
int MAX_SIZE = 20;
char c;
char arr[MAX_SIZE];
char revArr[MAX_SIZE];
while(c != EOF)
{
count = 0;
c = getchar();
arr[count++] = c;
getReverse(revArr, arr);
printf("%s", revArr);
if (c == '\n')
{
printf("\n");
count = 0;
}
}
}
void getReverse(char dest[], char src[])
{
int i, j, n = sizeof(src);
for (i = n - 1, j = 0; i >= 0; i--)
{
j = 0;
dest[j] = src[i];
j++;
}
}
You have quite a few problems in there. The first is that there is no prototype in scope for getReverse() when you use it in main(). You should either provide a prototype or just move getReverse() to above main() so that main() knows about it.
The second is the fact that you're trying to reverse the string after every character being entered, and that your input method is not quite right (it checks an indeterminate c before ever getting a character). It would be better as something like this:
count = 0;
c = getchar();
while (c != EOF) {
arr[count++] = c;
c = getchar();
}
arr[count] = '\0';
That will get you a proper C string albeit one with a newline on the end, and even possibly a multi-line string, which doesn't match your specs ("reads input from the standard input a line of characters"). If you want a newline or file-end to terminate input, you can use this instead:
count = 0;
c = getchar();
while ((c != '\n') && (c != EOF)) {
arr[count++] = c;
c = getchar();
}
arr[count] = '\0';
And, on top of that, c should actually be an int, not a char, because it has to be able to store every possible character plus the EOF marker.
Your getReverse() function also has problems, mainly due to the fact it's not putting an end-string marker at the end of the array but also because it uses the wrong size (sizeof rather than strlen) and because it appears to re-initialise j every time through the loop. In any case, it can be greatly simplified:
void getReverse (char *dest, char *src) {
int i = strlen(src) - 1, j = 0;
while (i >= 0) {
dest[j] = src[i];
j++;
i--;
}
dest[j] = '\0';
}
or, once you're a proficient coder:
void getReverse (char *dest, char *src) {
int i = strlen(src) - 1, j = 0;
while (i >= 0)
dest[j++] = src[i--];
dest[j] = '\0';
}
If you need a main program which gives you reversed characters for each line, you can do that with something like this:
int main (void) {
int count;
int MAX_SIZE = 20;
int c;
char arr[MAX_SIZE];
char revArr[MAX_SIZE];
c = getchar();
count = 0;
while(c != EOF) {
if (c != '\n') {
arr[count++] = c;
c = getchar();
continue;
}
arr[count] = '\0';
getReverse(revArr, arr);
printf("'%s' => '%s'\n", arr, revArr);
count = 0;
c = getchar();
}
return 0;
}
which, on a sample run, shows:
pax> ./testprog
hello
'hello' => 'olleh'
goodbye
'goodbye' => 'eybdoog'
a man a plan a canal panama
'a man a plan a canal panama' => 'amanap lanac a nalp a nam a'
Your 'count' variable goes to 0 every time the while loop runs.
Count is initialised to 0 everytime the loop is entered
you are sending the array with each character for reversal which is not a very bright thing to do but won't create problems. Rather, first store all the characters in the array and send it once to the getreverse function after the array is complete.
sizeof(src) will not give the number of characters. How about you send i after the loop was terminated in main as a parameter too. Ofcourse there are many ways and various function but since it seems like you are in the initial stages, you can try up strlen and other such functions.
you have initialised j to 0 in the for loop but again, specifying it INSIDE the loop will initialise the value everytime its run from the top hence j ends up not incrmenting. So remore the j=0 and i=0 from INSIDE the loop since you only need to get it initialised once.
check this out
#include <stdio.h>
#include <ctype.h>
void getReverse(char dest[], char src[], int count);
int main()
{
// *always* initialize variables
int count = 0;
const int MaxLen = 20; // max length string, leave upper case names for MACROS
const int MaxSize = MaxLen + 1; // add one for ending \0
int c = '\0';
char arr[MaxSize] = {0};
char revArr[MaxSize] = {0};
// first collect characters to be reversed
// note that input is buffered so user could enter more than MAX_SIZE
do
{
c = fgetc(stdin);
if ( c != EOF && (isalpha(c) || isdigit(c))) // only consider "proper" characters
{
arr[count++] = (char)c;
}
}
while(c != EOF && c != '\n' && count < MaxLen); // EOF or Newline or MaxLen
getReverse( revArr, arr, count );
printf("%s\n", revArr);
return 0;
}
void getReverse(char dest[], char src[], int count)
{
int i = count - 1;
int j = 0;
while ( i > -1 )
{
dest[j++] = src[i--];
}
}
Dealing with strings is a rich source of bugs in C, because even simple operations like copying and modifying require thinking about issues of allocation and storage. This problem though can be simplified considerably by thinking of the input and output not as strings but as streams of characters, and relying on recursion and local storage to handle all allocation.
The following is a complete program that will read one line of standard input and print its reverse to standard output, with the length of the input limited only by the growth of the stack:
int florb (int c) { return c == '\n' ? c : putchar(florb(getchar())), c; }
main() { florb('-'); }
..or check this
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
char *my_rev(const char *source);
int main(void)
{
char *stringA;
stringA = malloc(MAX); /* memory allocation for 100 characters */
if(stringA == NULL) /* if malloc returns NULL error msg is printed and program exits */
{
fprintf(stdout, "Out of memory error\n");
exit(1);
}
else
{
fprintf(stdout, "Type a string:\n");
fgets(stringA, MAX, stdin);
my_rev(stringA);
}
return 0;
}
char *my_rev(const char *source) /* const makes sure that function does not modify the value pointed to by source pointer */
{
int len = 0; /* first function calculates the length of the string */
while(*source != '\n') /* fgets preserves terminating newline, that's why \n is used instead of \0 */
{
len++;
*source++;
}
len--; /* length calculation includes newline, so length is subtracted by one */
*source--; /* pointer moved to point to last character instead of \n */
int b;
for(b = len; b >= 0; b--) /* for loop prints string in reverse order */
{
fprintf(stdout, "%c", *source);
len--;
*source--;
}
return;
}
Output looks like this:
Type a string:
writing about C programming
gnimmargorp C tuoba gnitirw

Resources