How to calculate frequency of characters in a string [duplicate] - c

This question already has an answer here:
C program: how to find the maximum/minimum frequency of a character in a string
(1 answer)
Closed 6 years ago.
I am a beginner with C programming so my code is very basic. It is to count the frequency of characters in a string. The program does run but the problem is that it displays each character as many times as it appears in the string. So, when I enter hello, I get "h occurs 1 times, e occurs 1 times, l occurs 2 times, l occurs 2 times, o occurs 1 times". How do i eliminate this and make the count for l appear only once?
for(i=0;str[i]!='\0';i++)
{
for(j=0;str[j]!='\0';j++)
{
if(str[i]==str[j])
count[i]++;
}
}
for(i=0;i<str[i]!='\0';i++)
printf("%c occurs %d times \n",str[i],count[i]);

I think building your own function which removes duplicated characters would help you in achieving what you are trying to do. But, there is no standard function that would help you in removing all the duplicates from a string. So try constructing a function to remove all the duplicated/repeated characters from a string and returns the string. Here's what your function would look like:
char* remove_duplicated(char* str, int size) {
int frequency[256] = {0};
char* new_str = malloc(size);
int new_size = 0;
for(int i=0; str[i]!='\0'; i++)
{
if(frequency[(unsigned char) str[i]] == 0) {
frequency[(unsigned char) str[i]]++;
new_str[new_size] = str[i];
new_size++;
}
}
new_str[new_size] = '\0';
return new_str;
}
Once you have constructed the above function, send the string in which you want to have the frequencies of characters measured and store the returned string. Something like this:
char* new_str = remove_duplicated(str, size);
Now in the double for loop that you are using, use new_str for your outer for loop and also use it for the for loop displaying count
for(i=0; new_str[i]!='\0'; i++)
{
for(j=0; str[j]!='\0'; j++)
{
if(new_str[i] == str[j])
count[i]++;
}
}
for(i=0; new_str[i]!='\0'; i++)
printf("%c occurs %d times \n", new_str[i], count[i]);
don't forget to free the malloced array in the remove_duplicated function:
free(new_str);
Here's an online demo: https://ideone.com/KnkwGX

You can use something like
int characters[128] = {0};
char string[] = "Hello, World!";
for(int i = 0; string[i] != '\0'; i++)
characters[(int)string[i]]++;
for(int i = 0; i < 128; i++)
if(characters[i] != 0)
printf("%c occurs %d times\n", (char)i, characters[i]);

It is going to be a little difficult to print the count of each letter uniquely with the way you have coded. Try the following way:
int frequency[122] = {0}; //ascii value of z is 122.
for(i=0;str[i]!='\0';i++)
{
frequency[str[i]]++;
}
for(i=0;i<=122;i++) {
if(frequency[i] != 0)
printf("%c occurs %d times\n", str[i], count[i]);
}

Related

The goal is to read two strings into 2 different variables. Then we count the number of "C" in each string and output the result

Here is what I did:
int main ()
{
int count = 0;
int i, j;
char firstLine[10000000];
char secondLine[10000000];
scanf("%s", firstLine);
scanf("%s", secondLine);
for (i=0;i<10000000;i++) {
if (firstLine[i] == 'C') {count++;}
}
for (j=0;j<10000000;j++) {
if (secondLine[j] == 'C') {count++;}
}
printf("%d", count);
return 0;
}
I think it makes sense but there is some sort of segmentation error according to my compiler. What am I missing?
For example, an input of AB
BBAAB should yield an output of 0.
Something like this should do the trick:
#define BUF_MAX 100
int main ()
{
int count1 = 0, count2 = 0;
char firstLine[BUF_MAX];
char secondLine[BUF_MAX];
fgets(firstLine,BUF_MAX,stdin);
for (int i = 0; firstLine[i] != 0; ++i)
if (firstLine[i] == 'C') ++count1;
fgets(secondLine,BUF_MAX,stdin);
for (int i = 0; secondLine[i] != 0; ++i)
if (secondLine[i] == 'C') ++count2;
printf("String 1 has %d C's\n", count1);
printf("String 2 has %d C's\n", count2);
return 0;
}
The BUF_MAX sets the maximum size of each line buffer, which I chose to be 100 (99 characters + the terminating null). If this isn't enough, make it bigger... say 500. But 10,000,000 is absurd... that could be the complete text of all of the Harry Potter books combined, or perhaps the complete works of Shakespeare!
The for loops continue as long as the character in the string is non-zero, i.e. until the terminating null character is encountered.
You should stop counting (break;) when you find a 0-terminator in your lines.
At the moment, you are going through an uninitialized garbage looking for random C

Manipulating dynamically allocated 2D char arrays in C

I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.

Passing an array of characters as function arguments

I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
replaceChars(char str[], char sChar[], char rChar)
{
int i,j;
printf("rChar is %c", rChar);
printf("sChar is %s", sChar);
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
if(str[i] == sChar[j])
{
str[i] = rChar;
//printf("The New String is %c", str[i]);
}
}
}
printf("The New String is %s", str);
}
void main()
{
char myString[36], schar[36], rchar;
printf("Please enter a string:");
scanf("%[^\n]s", &myString);
printf("Which characters to replace?");
scanf(" %[^\n]c", &schar);
printf("With which character?");
scanf(" %[^\n]c", &rchar);
replaceChars(myString, schar, rchar);
}
Two issues here.
First, when you loop through str and sChar:
I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
You use <= as your exit condition. Array indexes start from 0, so valid indexes are from 0 to length-1. You're going from 0 to length, so you're stepping of the end of the array. Reading past the end of an array invokes undefined behavior.
Change the conditions to use <:
for(i = 0; i < strlen(str); i++)
{
for(j = 0; j < strlen(sChar); j++)
{
The second problem is in how you're reading the values:
scanf("%[^\n]s", &myString);
...
scanf(" %[^\n]c", &schar);
...
scanf(" %[^\n]c", &rchar);
The %[] format specifier doesn't require any characters after it, and it requires a char * as a parameter which points to the first element of an array of char. In the first two cases, you're passing the address of an array instead of the array itself (which decays to a pointer) and you have an extra character after the %[] format that isn't needed. In the third case you pass a pointer to a single char when a pointer to multiple characters is expected by the format. Because you want to read a single char, you want to use the %c format specifier instead.
scanf("%35[^\n]", myString);
...
scanf(" %35[^\n]", schar);
...
scanf(" %c", &rchar);
Note also that the first two have a field width that limits the number of characters that are read so that you don't overrun the arrays.
Could you please let me know what mistake I am making here?
In addition to #dbush good answer, OP's code is unnecessarily inefficient.
Using the corrected code below, and assume the initial length of the str, sChar are S,C respectively.
for(i = 0; i < strlen(str); i++) {
for(j = 0; j < strlen(sChar); j++) {
if(str[i] == sChar[j]) {
str[i] = rChar;
}
}
}
The for(i = 0; i < strlen(str); i++) { and with the later str[i] = rChar; obliges the code to find the length of str up to S times and each strlen(str) requires O(S) operations.
If S was a non-trivial value, say 1000, this 1000*1000 could readily affect overall performance. A simply solution is to calculate the length once or look for the null character instead.
// for(i = 0; i < strlen(str); i++) {
S = strlen(str);
for(i = 0; i < S; i++) {
// or
for(i = 0; str[i]; i++) {
The same thing happens with the inner loop too. Yet a smart compiler can see that sChar does not change and may take advantage of understanding strlen() has no side effects that would cause for a different result. With such an optimization strlen(sChar) may be truly called once, even if strlen(sChar) in inside the higher for (i...) loop.
Still it is easy and idiomatic to just test for the null character.
// for(j = 0; j < strlen(sChar); j++)
// better as
for(j = 0; sChar[j]; j++)
Yet why does this not apply to the for(i = 0; i < strlen(str); i++) loop?
Within that loop, code can modify str[] and so the compiler cannot make the optimization as with for(j = 0; sChar[j]; j++).
This also begs the question, what should code do if the replacement character rChar is the null character?
As I see it, code could either continue, replacing with a '\0 multiple times or simple return after this first.
str[i] = rChar;
if (rChar == '\0') return; // Possible way to handle \0

A program that prints even and odd characters from a string

This is for Homework
I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.
#include <stdio.h>
#include <string.h>
int main(void) {
char *str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s", &str);
while (&str[i] < 41) {
if (i % 2 == 0) {
odd[j++] = *str[i];
} else {
even[k++] = *str[i];
}
i++;
}
printf("The even string is:%s\n ", even);
printf("The odd string is:%s\n ", odd);
return 0;
}
When I try and compile my program I get two warnings:
For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.
On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.
When I compile the program, I get random characters for both the even and odd string.
Any help would be appreciated!
this declaration is wrong:
char *str[41];
you're declaring 41 uninitialized strings. You want:
char str[41];
then, scanf("%40s" , str);, no & and limit the input size (safety)
then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)
while (str[i]) {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
if you want to use a pointer (assignement requirement), just define str as before:
char str[41];
scan the input value on it as indicated above, then point on it:
char *p = str;
And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:
while (*p) { // test end of string termination
if (i % 2 == 0) { // if ((p-str) % 2 == 0) { would allow to get rid of i
odd[j++] = *p;
} else {
even[k++] = *p;
}
p++;
i++;
}
(we have to increase i for the even/odd test, or we would have to test p-str evenness)
aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:
even[k] = odd[j] = '\0';
(as another answer states, check the concept of even & odd, the expected result may be the other way round)
There are multiple problems in your code:
You define an array of pointers char *str[41], not an array of char.
You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
You should limit the number of characters read by scanf.
You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
You should read the characters from str with str[i].
You should null terminate the even and odd arrays.
Here is a modified version:
#include <stdio.h>
int main(void) {
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
if (scanf("%40s", str) != 1)
return 1;
while (str[i] != '\0') {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = even[k] = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
return 0;
}
Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.
Many answers all ready point out the original code`s problems.
Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.
As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.
Alternative print: If code used "%.*s", the array does not need a null character termination.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[41];
printf("Enter a string (40 characters maximum): ");
fflush(stdout);
if (scanf("%40s", str) == 1) {
int i;
printf("The even string is:");
for (i = 0; str[i]; i++) {
if (i % 2 == 0) {
str[i / 2] = str[i]; // copy character to an earlier part of `str[]`
} else {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
}
return 0;
}
or simply
printf("The even string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 != 0) {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 == 0) {
putchar(str[i]);
}
}
printf("\n");
here is your solution :)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s" , str);
while (i < strlen(str))
{
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = '\0';
even[k] = '\0';
printf("The even string is:%s\n " , even);
printf("The odd string is:%s\n " , odd);
return 0;
}
solved the mistake in the declaration, the scanning string value, condition of the while loop and assignment of element of array. :)

Comparing 2 Strings together and saving the results

#include <stdio.h>
#define MAX 1000
void any(char s1[], char s2[], char s3[]);
int main()
{
char string1[MAX], string2[MAX], string3[MAX];
printf("Jepni stringen 1\n");
scanf("%s", &string1); //saving string 1
printf("Jepni stringen 2\n");
scanf("%s", &string2); //saving string 2
any(string1, string2, string3); /*comparing characters from string 2 to string 1 and saving the places where they are equal on third string */
printf("%d", string3[0]); //printing the first character of the third string
return 0;
}
void any(char s1[], char s2[], char s3[])
{
int i, j, k;
k = 0;
for (j = 0; j != '\0'; j++) {
for (i = 0; i != '\0'; i++) {
if (s1[i] == s2[j]) {
s3[k] = i;
j++;
k++;
}
}
}
}
I am trying to create a c program that scans 2 strings (saves them on string 1 and 2) than the program using function any will see character by character if the string 2 characters are equal with the string 1,If they are it will give the first position where they are found.In case nothing is found it displays a -1.The program asks for the first character that is equal,thats why i am printing always the first character from string 3.The program isnt working cuz it always prints -1.
Example if i put on string 1 dad
and on string 2 the character d
dhe program should display the 0 position
if i put dad on string 1
and on string 2 i put a
it should display 1.
First of all the for loop doesn't begin because the condition is that j shall be different from zero.In ASCII '\0' is zero (maybe not on all machines), so you rather want to check that s2[j] is different from zero.Same for i.
Another thing is that s3 is an array of chars, so putting s3[k]=i doesn't make it equal to '1' or '2', but to 1 or 2 (ASCII values), so you should add 48 to i (good till '9', then you'll have two digits), or print the string character per character, with the %d format specifier:
void any(char s1[], char s2[], char s3[])
{
int i, j, k;
k = 0;
for (j = 0; s2[j] != '\0'; j++) {
for (i = 0; s1[i] != '\0'; i++) {
if (s1[i] == s2[j]) {
s3[k] = i;
j++;
k++;
}
}
}
}
Maybe I'm missing some other error, try the code and run it to see if it's right (also remember to use the %d specifier to print s3).

Resources