I program in C. I'm supposed to create a program which identifies what is the most common character in a string and what's the second most common character.
I'm not sure why, but it's not working. the program should put into an integer the location of it. Not a pointer but if the most common is str1[i] then it will put into an integer the value of i. And so in the second most common. If it is str1[j] than it should put into an integer the value of j. then, it's supposed to replace the most commons with the second most common. The replacement function works, there's probably a problem in the loops although I can't figure out what is it.
Here's what I have (assume all of the integers and strings are declared in the beginning):
void stringReplace(char str1[], char ch1, char ch2);
int main()
{
char str1[100];
char ch1, ch2;
int i, j, p, n, len, counter1, counter2, first, second, times;
printf("Please enter the string - maximum = 100 characters:\n");
printf("User input: ");
gets(str1);
len = strlen(str1);
for(i = 0 ; i < len ; i++)
{
counter1 = 0;
for(j = 0 ; j < len ; j++)
{
if(str1[i] == str1[j])
{
counter1++;
}
if(counter1 > counter2)
{
first = i;
}
}
counter2 = counter1;
} //character which shows up most - found.
counter2 = 0;
for(p = 0 ; p < len ; p++)
{
for(n = 0 ; n < len ; n++)
{
if(str1[p] == str1[n])
{
counter1++;
}
if(counter1 < first && counter1 > counter2)
{
second = p;
}
}
counter2 = counter1;
}
ch1 = str1[first];
ch2 = str1[second];
stringReplace(str1, ch1, ch2);
puts(str1);
return 0;
}
void stringReplace(char str1[], char ch1, char ch2)
{
int i, j, len;
len = strlen(str1);
for(i = 0 ; i <= len ; i++)
{
if(str1[i] == ch1)
{
str1[i] = ch2;
}
}
}
Where's the problem ?
So you want to find the n max numbers in a string, being n=2, right?
I did a little working example for you. The code differs slightly from yours but it works well.
#include <stdio.h>
int main(int argc, char* argv[])
{
char str[] = "Algorithms Are Funnnn!\0";
int i=0;
int offset=33;
int ocurrs[94] = {0}; //considering from 33 to 126 (valid chars - ASCII Table [0-127]).
int max[2]={0};
while(str[i])
ocurrs[str[i++]-offset]++;
for(i=0; i<94; i++)
if(ocurrs[i]>ocurrs[max[1]]){
max[0] = max[1];
max[1] = i;
}
else if(ocurrs[i]>ocurrs[max[0]])
max[0]=i;
printf("chars '%c'(%d times) and '%c'(%d times) occurred most.\n",
offset+max[1], ocurrs[max[1]], offset+max[0], ocurrs[max[0]]);
return 0;
}
Also, try to stay away from gets as it's totally unsafe.
If you want to grab 100 chars max, use this instead:
char buffer[100];
fgets(buffer, 100, stdin);
Regards.
Can't resist to find an answer with some loops, without the populate occurence technique.
Very fun to code.
#include <string.h>
#include <stdio.h>
int main( void ) {
char szInput[] = "ONE DOES NOT SIMPLY WALK INTO MORDOR!";
int len = strlen( szInput );
int MaxCountSoFar_1 = 0;
int MaxIndexSoFar_1 = -1;
int MaxCountSoFar_2 = 0;
int MaxIndexSoFar_2 = -1;
int i, j, CountThatOne;
for ( i = 0; i < len; ++i ) {
if ( szInput[ i ] == ' ' ) continue;
// count that char
CountThatOne = 1;
// don't start from 0, they are already "counted"
for ( j = i + 1; j < len; ++j ) {
if ( szInput[ i ] == szInput[ j ] ) ++CountThatOne;
}
if ( CountThatOne > MaxCountSoFar_1 ) {
// push old first max to new second max
MaxCountSoFar_2 = MaxCountSoFar_1;
MaxIndexSoFar_2 = MaxIndexSoFar_1;
// new first max
MaxCountSoFar_1 = CountThatOne;
MaxIndexSoFar_1 = i;
} else {
// catch second one, but not if equal to first
if ( CountThatOne > MaxCountSoFar_2 && szInput[ i ] != szInput[ MaxIndexSoFar_1 ] ) {
MaxCountSoFar_2 = CountThatOne;
MaxIndexSoFar_2 = i;
}
}
}
if ( MaxIndexSoFar_1 >= 0 ) {
printf( "Most seen char is %c, first seen at index %d\n", szInput[ MaxIndexSoFar_1 ], MaxIndexSoFar_1 );
if ( MaxIndexSoFar_2 >= 0 ) {
printf( "Second Most seen char is %c, first seen at index %d\n", szInput[ MaxIndexSoFar_2 ], MaxIndexSoFar_2 );
}
}
return 0;
}
Related
I need to make a program that will print characters in a word on how frequent it is used. The unique characters will be printed in increasing order (spaces are ignored), if there are ties the character with lower ascii value will be printed first.
For an example if the input is hello world, the letters "h", "e", "w", "r" and "d" are only used once, the character "o" is used twice and the character "l" is used thrice. Since h,e,w,r,d are tie we should sort it into d,e,h,r,w. Then next would be o since it is used twice and then last is l. Thus if the input is hello world the output must be dehrwol. On my current program the problem is that when there are ties, it would not sort it alphabetically so the output is hewrdol instead of dehrwol.
This is the code I have written
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int times[256];
int cmpLetters(const void* a, const void* b)
{
return (times[*(char*)a] > times[*(char*)b]) - (times[*(char*)a] < times[*(char*)b]);
}
int main()
{
char letters[256];
int i, j, k, lnum, t;
char s[1000];
fgets(s, sizeof(s), stdin);
// Init occurrences as 0
memset(times, 0, sizeof(times));
for (i = lnum = 0; s[i] != '\0'; i++)
if (times[s[i]]++ == 0)
letters[lnum++] = s[i];
// Sort letters by number of occurrences
qsort(letters, lnum, sizeof(char), cmpLetters);
char* new = malloc(sizeof(char) * (i + 1));
for (j = k = 0; j < lnum; j++)
for (i = 0; i < times[letters[j]]; i++)
new[k++] = letters[j];
// new[k] = '\0';
for (i = 0; i<lnum; i++)
{
if(letters[i] != '\n' && letters[i] !=' ')
printf("%c",letters[i]);
}
printf("\n\n");
return 0;
}
In this for loop
for (i = lnum = 0; s[i] != '\0'; i++)
if (times[s[i]]++ == 0)
letters[lnum++] = s[i];
you are not checking whether s[i] represents a letter.
The comparison function
int cmpLetters(const void* a, const void* b)
{
return (times[*(char*)a] > times[*(char*)b]) - (times[*(char*)a] < times[*(char*)b]);
}
compares only characters without comparing also their frequencies.
This code snippet
char* new = malloc(sizeof(char) * (i + 1));
for (j = k = 0; j < lnum; j++)
for (i = 0; i < times[letters[j]]; i++)
new[k++] = letters[j];
does not make sense because the array new is not used further in the program. It only produces a memory leak.
The program will be simpler if to introduce a structure that contains two data members that store a letter and its frequency.
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct Pair
{
char c;
size_t n;
};
int cmp( const void *a, const void *b )
{
const struct Pair *p1 = a;
const struct Pair *p2 = b;
int result = ( p2->n < p1->n ) - ( p1->n < p2->n );
if (result == 0)
{
result = ( p2->c < p1->c ) - ( p1->c < p2->c );
}
return result;
}
int main( void )
{
enum { N = 1000} ;
char s[N];
fgets( s, sizeof( s ), stdin );
size_t n = 0;
for (size_t i = 0; s[i] != '\0'; ++i)
{
if (isalpha( ( unsigned char )s[i] ))
{
size_t j = 0;
while (j != i && s[j] != s[i]) ++j;
n += j == i;
}
}
if (n != 0)
{
struct Pair pairs[n];
memset( pairs, 0, n * sizeof( struct Pair ) );
for (size_t i = 0, m = 0; s[i] != '\0'; i++)
{
if (isalpha( ( unsigned char )s[i] ))
{
size_t j = 0;
while (j != m && pairs[j].c != s[i]) ++j;
if (j == m)
{
pairs[m].c = s[i];
++pairs[m].n;
++m;
}
else
{
++pairs[j].n;
}
}
}
qsort( pairs, n, sizeof( *pairs ), cmp );
for (size_t i = 0; i < n; i++)
{
putchar( pairs[i].c );
}
putchar( '\n' );
}
}
The program output might look like
hello world
dehrwol
I'm wondering why my duplicate check is giving me wrong output. The idea is to built a nested loop, that compares every following letter in an array, with the initial loop's one. However, if I print the results, the function gives back true when A = K e.g. and I don't understand that behaviour. Anyone able to explain what's happening here?
for (int n = 0; n < strlen(argv[1]) ; n++)
{
for (int i = 0; i < strlen(argv[1]) ; i++)
{
if (argv[1][n] == argv[1][i + 1])
{
printf("argv[1][n] = %c\n", argv[1][n]);
printf("argv[1][i] = %c\n", argv[1][i]);
printf("Error.\n");
return 0;
}
}
}
A more efficient way to check for duplicate chars in a string. Only requires one for-loop instead of a nested pair of loops. Assumes an 8-bit char - hence 256 as array size.
size_t table[256] = {0};
size_t positions[256] = {0};
const char* sz = argv[1];
const size_t len = strlen(argv[1]);
for (size_t i = 0; i < len; i++)
{
unsigned char index = (unsigned char)(sz[i]);
table[index]++;
if (table[index] > 1)
{
printf("duplicate char %c found at index %d. Originally seen at index %d\n", sz[i], i, (int)(positions[index]));
return 0;
}
else
{
positions[index] = i;
}
}
These for loops
for (int n = 0; n < strlen(argv[1]) ; n++)
{
for (int i = 0; i < strlen(argv[1]) ; i++)
{
if (argv[1][n] == argv[1][i + 1])
{
//...
}
}
}
do not make a sense because argv[1][n] can be the same letter at the same position as argv[1][i+1] because the inner loop starts from 0.
Also you are outputting a letter at position i
printf("argv[1][i] = %c\n", argv[1][i]);
but in the preceding if statement you are checking a letter at the position i + 1.
The loops can look the following way
for ( size_t i = 0, n = strlen( argv[1] ); i < n ; i++ )
{
for ( size_t j = i + 1; j < n; j++ )
{
if ( argv[1][i] == argv[1][j] )
{
printf( "argv[1][i] = %c\n", argv[1][i]);
printf( "argv[1][j] = %c\n", argv[1][j]);
printf("Error.\n");
return 0;
}
}
}
Instead of the inner loop you could use the standard C function strchr. Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
int unique( const char *s )
{
while ( *s && !strchr( s + 1, *s ) ) ++s;
return *s == '\0';
}
int main(void)
{
char *s = "12345";
printf( "\"%s\" -> %d\n", s, unique( s ) );
s = "12341";
printf( "\"%s\" -> %d\n", s, unique( s ) );
return 0;
}
The program output is
"12345" -> 1
"12341" -> 0
You may call the function passing as an argument the command line argument argv[1]. For example
If ( !unique( argv[1] ) ) puts( "Error." );
Why A = K is because you are printing the i-th index printf("argv[1][i] = %c\n", argv[1][i]); when you are checking i+1th index if (argv[1][n] == argv[1][i + 1]). You are printing the wrong character that is checked with your if statement.
Also, be careful on that i+1 and your loop condition.
I need to build a program that receives up to 30 chars from the user, and then to play with it.
For example, I need to reverses the sentence and then print it, or to rotate it.
I have been trying to copy the words of the sentence one by one to a matrix of [30][31], but it does not working... any ideas?
I cannot use pointers...
thanks for the help :)
#include <stdio.h>
#include <string.h>
void main(){
int i=0,
j=0,
wrongData=0,
charCounter=0,
word=0,
letter=0;
char st[100],
arr[100]={0},
mat[30][31]={0};
printf("Please, enter your sentence >");
gets(st);
while(i<strlen(st)){
if('A'<=st[i] && st[i]<='Z'){
charCounter++;
arr[j] = st[i];
i++;
j++;
} else if(st[i]==' '){
arr[j] = ' ';
i++;
j++;
while(st[i] == ' '){
i++;
}
} else if(st[i]=='\0'){
arr[j] = '\0';
break;
} else {
puts("ERROR: Incorrect data, try again.");
wrongData=1;
break;
}
if(wrongData==0){
if(charCounter>30){
puts("ERROR: Incorrect data, try again.");
}
}
}
puts(st);
puts(arr);
if(arr[j]==' '){
word++;
}
while(arr[j]!=' ' && letter<32){
strcpy(mat[word],arr);
}
if(arr[j]=='\0'){
mat[word][letter]=arr[j];
}
puts(mat[word]);
}
Taking into account your comment
the problem is that i need to reverse the words not the letters... for
example: if the string is cats hates dogs, i need to get at the end
dogs hates cats
then I think you mean something as the following
#include <stdio.h>
#include <ctype.h>
#include <string.h>
char * reverse_words( char s[] )
{
for ( char *p = s, *q = s; *p; p = q )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
q = p;
while ( *q && !isspace( ( unsigned char )*q ) ) ++q;
for ( size_t i = 0; i < ( q - p ) / 2; i++ )
{
char c = p[i];
p[i] = q[-i-1];
q[-i-1] = c;
}
}
for ( size_t i = 0, n = strlen( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
return s;
}
int main( void )
{
char s[] = "cats hates dogs";
puts( s );
puts( reverse_words( s ) );
return 0;
}
The program output is
cats hates dogs
dogs hates cats
Here is another approach. The idea is to go through the string and record the index where each word starts and ends. Then the words can be printed in reverse order afterwards. (btw - it will also be easy to rotate the words).
#include<stdio.h>
#include <string.h>
int main() {
char st[100] = "here we go again";
int start[30] = { 0 };
int end[30] = { 0 };
int count = 0;
int len = strlen(st);
int i, j;
// Find start and end index of each word
start[0] = 0;
for(i = 0; i < len; ++i)
{
if (st[i] == ' ')
{
end[count] = i;
++count;
start[count] = i + 1;
}
}
end[count] = len;
// Print the words in reverse order
for(i=count; i >= 0; --i)
{
for (j = start[i]; j < end[i]; ++j)
{
printf("%c", st[j]);
}
printf(" ");
}
printf("\n");
return 0;
}
output:
again go we here
fix your approach like this:
#include <stdio.h>
//#include <string.h>
#define MAX_LEN 30
int main(void){
int i, j, n, word;
char st[100], arr[100], mat[MAX_LEN / 2][MAX_LEN + 1];
printf("Please, enter your sentence (up to %d chars and A-Z or space)\n>", MAX_LEN);fflush(stdout);
scanf("%99[^\n]%*c", st);
//validate and reduce of spaces
for(j = i = 0; st[i]; ++i){
if(i > MAX_LEN){
fputs("ERROR: Incorrect data, try again.\n", stderr);
return 1;
}
if('A'<=st[i] && st[i]<='Z'){
arr[j++] = st[i];
} else if(st[i]==' '){
arr[j++] = ' ';
while(st[++i] == ' ')//Skip a continuous space
;
--i;//one back for next loop
} else {
fputs("ERROR: Incorrect data, try again.\n", stderr);
return 1;
}
}
arr[j] = '\0';//st[i]=='\0' never become true in loop
#if DEBUG
puts(st);
puts(arr);
#endif
//split to word
for(word = j = i = 0; arr[i];){
while(arr[i] == ' ')
++i;//skip space
while(arr[i] != ' ' && arr[i] != '\0')
mat[word][j++] = arr[i++];
mat[word++][j] = '\0';
j = 0;
}
#if DEBUG
for(i = 0; i < word; ++i)
puts(mat[i]);
#endif
puts("reverse word");
for(i = 0; i < word; ++i){
if(i)
putchar(' ');
printf("%s", mat[word-1-i]);
}
puts("\nrotate word");
printf("Please, enter number of rotate\n>");fflush(stdout);
scanf("%d", &n);
for(i = 0; i < word; ++i){
if(i)
putchar(' ');
printf("%s", mat[(i+n)%word]);//rotate left
}
}
I am having an issue with this program, I want it to only displays words in the input once and count each time they appear, however it is displaying every word entered.
for example if i enter
"this should only only appear appear once"
then i want the program to output
this 1
should 1
only 2
appear 2
once 1
Any help would be appreciated.
#include <stdio.h>
#include <string.h>
#define ROW 1000
#define COL 50
int read_input(char *str, int n);
int main(void)
{
char str[ROW];
char stringSeperate[ROW][COL] = { };
const char *s= " ,.!";
char *p;
int freq[ROW];
int i = 0;
int wordCount = 0;
int pos = 0;
read_input(str, ROW);
p = strtok(str,s);
i = 1;
while(p !=NULL) {
wordCount = i;
for(i = 0; i < wordCount; i++) {
if (strcmp(p, stringSeperate[i]) != 0)
pos = 1;
else
pos = i;
}
if (pos == 1) {
strcpy(stringSeperate[i], p);
freq[i++]++;
}
else
freq[pos]++;
p = strtok(NULL,s);
}
for ( i = 1; i <= wordCount; i++ ) {
printf("Word: %s\t Number: %d\n",stringSeperate[i], freq[i]);
}
return 0;
}
int read_input(char *str, int n)
{
int ch, i = 0;
while((ch = getchar()) != '\n') {
if ( i < n ) {
*str++ = ch;
i++;
}
}
*str = '\0';
return i;
}
You invoked undefined behavior by using value of uninitialized variable freq having automatic storage duration, which is indeterminate.
Initialize it like int freq[ROW] = {0};
Also you should
1. Change initialization of stringSeperate to standard: empty initlalizer is not allowed, so it should be like
char stringSeperate[ROW][COL] = {{0}};
2. Remove extra printing to match the desired output: change
printf("Word: %s\t Number: %d\n",stringSeperate[i], freq[i]);
to
printf("%s %d\n",stringSeperate[i], freq[i]);
3. Check the length of input in order not to cause buffer overrun. Change
if ( i < n ) {
in read_input to
if ( i < n - 1 ) {
in order to make room for terminating null-characteer.
I've nearly finished my anagram solver program where I input two strings and get the result of whether they are anagrams of each other. For this example i'm using 'Payment received' and 'Every cent paid me'.
The problem i'm getting is when I output the letterCount arrays, letterCount1 is incorrect (it doesn't think there is a character 'd' but there is.) but letterCount2 is correct.
Can anyone see a problem with this because i'm completely baffled?
#include <stdio.h>
#include <string.h>
int checkAnagram(char string1[], char string2[])
{
int i;
int count = 0, count2 = 0;
int letterCount1[26] = {0};
int letterCount2[26] = {0};
for(i = 0; i < strlen(string1); i++)
{
if(!isspace(string1[i]))
{
string1[i] = tolower(string1[i]);
count++;
}
}
for(i = 0; i < strlen(string2); i++)
{
if(!isspace(string2[i]))
{
string2[i] = tolower(string2[i]);
count2++;
}
}
if(count == count2)
{
for(i = 0; i < count; i++)
{
if(string1[i] >='a' && string1[i] <= 'z')
{
letterCount1[string1[i] - 'a'] ++;
}
if(string2[i] >='a' && string2[i] <= 'z')
{
letterCount2[string2[i] - 'a'] ++;
}
}
printf("%s\n", string1);
for(i = 0; i < 26; i++)
{
printf("%d ", letterCount1[i]);
printf("%d ", letterCount2[i]);
}
}
}
main()
{
char string1[100];
char string2[100];
gets(string1);
gets(string2);
if(checkAnagram(string1, string2) == 1)
{
printf("%s", "Yes");
} else
{
printf("%s", "No");
}
}
That's because your count holds the count of non-space characters, but you keep the strings with the spaces.
For example, the string "hello world" has 11 characters, but if you run it through the loops your count will be 10 (you don't count the space). However, when you later go over the strings and count the appearance of each letter, you will go over the first 10 characters, therefore completely ignoring the last character - a 'd'.
To fix it, you need to go over all characters of the string, and only count the alphanumeric ones.
I fixed it for you:
#include <stdio.h>
#include <string.h>
int checkAnagram(char string1[], char string2[])
{
int i;
int count = 0, count2 = 0;
int letterCount1[26] = {0};
int letterCount2[26] = {0};
int len1 = strlen(string1);
int len2 = strlen(string2);
for(i = 0; i < len1; i++)
{
if(!isspace(string1[i]))
{
string1[i] = tolower(string1[i]);
count++;
}
}
for(i = 0; i < len2; i++)
{
if(!isspace(string2[i]))
{
string2[i] = tolower(string2[i]);
count2++;
}
}
if(count == count2)
{
for (i=0; i<len1; i++)
if (!isspace(string1[i]))
letterCount1[string1[i]-'a']++;
for (i=0; i<len2; i++)
if (!isspace(string2[i]))
letterCount2[string2[i]-'a']++;
int flag = 1;
for(i = 0; flag && i < 26; i++)
if (letterCount1[i] != letterCount2[i])
flag = 0;
return flag;
}
return 0;
}
main()
{
char string1[100];
char string2[100];
gets(string1);
gets(string2);
if(checkAnagram(string1, string2) == 1)
{
printf("%s", "Yes");
} else
{
printf("%s", "No");
}
}
First, don't calculate an string's length inside a loop. I extracted them into len1 and len2 variables.
Second, your loop was wrong! You shouldn't go up to count, you should go up to that string's length.
Third, you didn't return anything from checkAnagram function.