I've been asked to find the number of characters that are compared during naive string matching. This was the function we were asked to implement:
// Count the number of characters compared while finding all occurences of the pattern in the given text
// Characters must be matched from left to right
int charactersCompared(char *pattern, char *text);
So if the text is:"ABCEDF" and the pattern is: "EF" the number of characters I would compare using the brute force method would be 6 (comparing the first letter of text with the first letter of the pattern. If it does not match, compare the second letter of the text with the first letter of the pattern again.
If it matches, continue with the comparing the next letters of both text and pattern and so on)
After figuring out a logic with many example cases, I implemented the above function this way:
int charactersCompared(char *pattern, char *text)
{
int i,j,comp=0;
int flag;
for(i=0;text[i]!='\0';i++) //iterating through all the letters of text
{
for(j=0;pattern[j]!='\0';j++)
{
comp++; //to count one comparision.
if(text[i+j]==pattern[j]) //to check if similar to pattern
{
flag=1;
continue;
}
else
{
if(flag==1)
{
flag=0;
comp--;
}
break;
}
}
}
//printf("VALUE OF C=%d\n",comp);
return comp;
}
This works fine for the pair(ABCDEF,EF) (where the count is 6) but not for other test cases which include multiple occurrences of the pattern in text such as:
Text: ABCDEFGHEIEF
Pattern: EF
I'm supposed to get 14 comparisions whereas my output is 12. I don't understand where I am missing out.
If anyone can point out what is the faulty logic, it'd be of great help. Or if there is an easier way to do this, suggestions appreciated. The only constraint is that the method has to be a brute force method (i.e I can't really change the part where i compare each character of each string).
Thank you for your time!
Please note that in worse case is n(m-n+1) , where n is length of pattern and m is length of text. Now, Since you only want to compute comparisons, there's no need for variable flag. Prefer KISS principle.
for(i=0;text[i]!='\0';i++) //iterating through all the letters of text
{
for(j=0;pattern[j]!='\0';j++)
{
comp++; //to count one comparison.
if(text[i+j]==pattern[j]) //to check if similar to pattern
continue;
break;
}
}
printf("VALUE OF C=%d\n",comp);
So i figured out why my program incremented comp extra number of times in the answer posted by #E.N.D . It was because the outer for loop continued until each letter in the text was not compared. But when we do it manually, it's only until the the number of letters remaining in text while comparision are equal to or more than the number of letters in pattern. So i changed a condition
int charactersCompared(char *pattern, char *text)
{
int i,j,comp=0; //int flag;
int lenp=length(pattern),lent=length(text);
for(i=0;i<=lent-lenp;i++)
{
for(j=0;pattern[j]!='\0';j++)
{
comp++;
if(text[i+j]==pattern[j])
{
continue;
}
break;
}
}
//printf("VALUE OF C=%d\n",c);
return comp;
}
This makes sense and works! Thanks for those who tried to answer!
Related
I'm trying to create a complete C program to read ten alphabets and display them on the screen. I shall also have to find the number of a certain element and print it on the screen.
#include <stdio.h>
#include <conio.h>
void listAlpha( char ch)
{
printf(" %c", ch);
}
int readAlpha(){
char arr[10];
int count = 1, iterator = 0;
for(int iterator=0; iterator<10; iterator++){
printf("\nAlphabet %d:", count);
scanf(" %c", &arr[iterator]);
count++;
}
printf("-----------------------------------------");
printf("List of alphabets: ");
for (int x=0; x<10; x++)
{
/* Iām passing each element one by one using subscript*/
listAlpha(arr[x]);
}
printf("%c",arr);
return 0;
}
int findTotal(){
}
int main(){
readAlpha();
}
The code should be added in the findTotal() element. The output is expected as below.
Output:
List of alphabets : C C C A B C B A C C //I've worked out this part.
Total alphabet A: 2
Total alphabet B: 2
Total alphabet C: 6
Alphabet with highest hit is C
I use an array to count the number of the existence of each character,
I did this code but the display of number of each character is repeated in the loop
int main()
{
char arr[100];
printf("Give a text :");
gets(arr);
int k=strlen(arr);
for(int iterator=0; iterator<k; iterator++)
{
printf("[%c]",arr[iterator]);
}
int T[k];
for(int i=0;i<k;i++)
{
T[i]=arr[i];
}
int cpt1=0;
char d;
for(int i=0;i<k;i++)
{int cpt=0;
for(int j=0;j<k;j++)
{
if(T[i]==T[j])
{
cpt++;
}
}
if(cpt>cpt1)
{
cpt1=cpt;
d=T[i];
}
printf("\nTotal alphabet %c : %d \n",T[i],cpt);
}
printf("\nAlphabet with highest hit is : %c\n",d,cpt1);
}
There is no way to get the number of elements You write in an array.
Array in C is just a space in the memory.
C does not know what elements are actual data.
But there are common ways to solve this problem in C:
as mentioned above, create an array with one extra element and, fill the element after the last actual element with zero ('\0'). Zero means the end of the actual data. It is right if you do not wish to use '\0' among characters to be processed. It is similar to null-terminated strings in C.
add the variable to store the number of elements in an array. It is similar to Pascal-strings.
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE 10
char array[ARRAY_SIZE + 1];
int array_len(char * inp_arr) {
int ret_val = 0;
while (inp_arr[ret_val] != '\0')
++ret_val;
return ret_val;
}
float array_with_level[ARRAY_SIZE];
int array_with_level_level;
int main() {
array[0] = '\0';
memcpy(array, "hello!\0", 7); // 7'th element is 0
printf("array with 0 at the end\n");
printf("%s, length is %d\n", array, array_len(array));
array_with_level_level = 0;
const int fill_level = 5;
int iter;
for (iter = 0; iter < fill_level; ++iter) {
array_with_level[iter] = iter*iter/2.0;
}
array_with_level_level = iter;
printf("array with length in the dedicated variable\n");
for (int i1 = 0; i1 < array_with_level_level; ++i1)
printf("%02d:%02.2f ", i1, array_with_level[i1]);
printf(", length is %d", array_with_level_level);
return 0;
}
<conio.h> is a non-standard header. I assume you're using Turbo C/C++ because it's part of your course. Turbo C/C++ is a terrible implementation (in 2020) and the only known reason to use it is because your lecturer made you!
However everything you actually use here is standard. I believe you can remove it.
printf("%c",arr); doesn't make sense. arr will be passed as a pointer (to the first character in the array) but %c expects a character value. I'm not sure what you want that line to do but it doesn't look useful - you've listed the array in the for-loop.
I suggest you remove it. If you do don't worry about a \0. You only need that if you want to treat arr as a string but in the code you're handling it quite validly as an array of 10 characters without calling any functions that expect a string. That's when it needs to contain a 0 terminator.
Also add return 0; to the end of main(). It means 'execution successful' and is required to be conformant.
With those 3 changes an input of ABCDEFGHIJ produces:
Alphabet 1:
Alphabet 2:
Alphabet 3:
Alphabet 4:
Alphabet 5:
Alphabet 6:
Alphabet 7:
Alphabet 8:
Alphabet 9:
Alphabet 10:-----------------------------------------List of alphabets: A B C D E F G H I J
It's not pretty but that's what you asked for and it at least shows you've successfully read in the letters. You may want to tidy it up...
Remove printf("\nAlphabet %d:", count); and insert printf("\nAlphabet %d: %c", count,arr[iterator]); after scanf(" %c", &arr[iterator]);.
Put a newline before and after the line of minus signs (printf("\n-----------------------------------------\n"); and it looks better to me.
But that's just cosmetics. It's up to you.
There's a number of ways to find the most frequent character. But at this level I recommend a simple nested loop.
Here's a function that finds the most common character (rather than the count of the most common character) and if there's a tie (two characters with the same count) it returns the one that appears first.
char findCommonest(const char* arr){
char commonest='#'; //Arbitrary Bad value!
int high_count=0;
for(int ch=0;ch<10;++ch){
const char counting=arr[ch];
int count=0;
for(int c=0;c<10;++c){
if(arr[c]==counting){
++count;
}
}
if(count>high_count){
high_count=count;
commonest=counting;
}
}
return commonest;
}
It's not very efficient and you might like to put some printfs in to see why!
But I think it's at your level of expertise to understand. Eventually.
Here's a version that unit-tests that function. Never write code without a unit test battery of some kind. It might look like chore but it'll help debug your code.
https://ideone.com/DVy7Cn
Footnote: I've made minimal changes to your code. There's comments with some good advice that you shouldn't hardcode the array size as 10 and certainly not litter the code with that value (e.g. #define ALPHABET_LIST_SIZE (10) at the top).
I have used const but that may be something you haven't yet met. If you don't understand it and don't want to learn it, remove it.
The terms of your course will forbid plagiarism. You may not cut and paste my code into yours. You are obliged to understand the ideas and implement it yourself. My code is very inefficient. You might want to do something about that!
The only run-time problem I see in your code is this statement:
printf("%c",arr);
Is wrong. At this point in your program, arr is an array of char, not a single char as expected by the format specifier %c. For this to work, the printf() needs to be expanded to:
printf("%c%c%c%c%c%c%c%c%c%c\n",
arr[0],arr[1],arr[2],arr[3],arr[4],
arr[5],arr[6],arr[7],arr[8],arr[9]);
Or: treat arr as a string rather than just a char array. Declare arr as `char arr[11] = {0};//extra space for null termination
printf("%s\n", arr);//to print the string
Regarding this part of your stated objective:
"I shall also have to find the number of a certain element and print it on the screen. I'm new to this. Please help me out."
The steps below are offered to modify the following work
int findTotal(){
}
Change prototype to:
int FindTotal(char *arr);
count each occurrence of unique element in array (How to reference)
Adapt above reference to use printf and formatting to match your stated output. (How to reference)
I'm doing a course online in C and this is the assignment:
You are still conducting linguistic research! This time, you'd like to
write a program to find out how many letters occur multiple times in a
given word. Your program should read a word from the input and then
sort the letters of the word alphabetically (by their ASCII codes).
Next, your program should iterate through the letters of the word and
compare each letter with the one following it. If these equal each
other, you increase a counter by 1, making sure to then skip ahead far
enough so that letters that occur more than twice are not counted
again. You may assume that the word you read from the input has no
more than 50 letters, and that the word is all lowercase.
The solution they provide:
#include <stdio.h>
int main(void)
{
char word[51];
int length = 0;
int i, j;
char swap;
int repeats = 0;
scanf("%s", word);
while (word[length]!='\0')
length++;
//Sort the word by alphabetical order
for(j=0;j<length-1; j++) {
for(i=0;i<length-1;i++) {
if (word[i] > word[i+1]) {
swap = word[i];
word[i] = word[i+1];
word[i+1] = swap;
}
}
}
i = 0;
//Check for repeating characters in the sorted word
while (i<length-1) {
if (word[i]==word[i+1]) {
repeats++;
j=i+2;
//Continues through the word until it reaches a new character
while (j<length && word[i]==word[j])
j++;
i = j;
} else {
i++;
}
}
printf("%d", repeats);
return 0;
}
I understand everything up to code "//check for repeating characters in the sorted word//".
Specifically I don't understand the purpose or logic of "j=i+2" (especially the "+2") and how it relates to the next section of code "//continues through the word until it reaches a new character". I don't think this was adequately explained in the tutorials provided by the course.
Any insight or feedback is much appreciated.
Imagine your word is printed on paper, and you examine it through a small hole in a cardboard sheet. You can only see 2 letters at a time.
First, look at the beginning of the word. Identical letters? If not, shift by 1 position and repeat. If yes:
You found one repeated letter. Now you should find where the repeated run ends. To do that, shift your examination hole to the end of the repeated run.
It is possible to do this shift correctly in several ways. The way they implemented is until the first of the two visible letters is different from the repeated letters you found earlier. To do that, first you should shift by 2 positions, because at that position in code you know that the two letters are identical. But you could shift by 1 position instead ā that would be correct too.
Another correct implementation ā shift until you see two different letters in the hole. This may be easier to implement and more intuitive.
Input format: The first line of input gives the number the input strings (without spaces and of maximum 100 length
and in lowercase). Then there is following n lines, each containing a string.
Output format: N lines of output, each line has either YES or NO following by newline. (YES if string is a magic square palindrome otherwise NO)
Sample Input:
4
satorarepotenetoperarotas
aba
abba
abcabacba
Sample Output:
YES
NO
YES
NO
So i have written the following code.But in my program the output gets displayed immediately after the input and it takes only one input at a time.
PS:If you have any suggestions on how to make the code more efficient,please add them in your answer.Thanks
#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{ int num_input,l;
scanf("%d",&num_input);
for(l=0;l<num_input;l++)
{
char str[100];
char i = 0;
int sq,j,k;
scanf("%s", str);
while(str[i]!='\0')
{
++i;
}
sq = sqrt(i);
if(i== sq*sq)
{
if(i%2==0)
{
for(j=0;j<=i/2;j++)
{
if((str[j]==str[i-j-1])&&(str[j+sq]==str[i-j-sq-1]))
{
if(j==i/2)
{
printf("YES\n");
}
}
else
{ if(j==i/2)
{
printf("NO\n");
}
}
}
}
if(i%2!=0)
{
for(k=0;k<=i/2;k++)
{
if((str[k]==str[i-k-1])&&(str[k+sq]==str[i-k-sq-1]))
{ if(k==i/2)
{
printf("YES\n");
}}
else
{if(j==i/2)
{
printf("NO\n");
}}
}
}
}
else
{
printf("NO\n");
}
}
return 0;
}
The problem of 'mixed' output and input is caused by the fact, that you take one string per calculation. If you want to scan the whole input, then display the output, you should... do exactly that. Simple approach how to do it, given that you know how many strings will be typed:
After you scan the number of strings with int num_input; scanf("%d",&num_input);, you can create a two-dimensional array of characters sized as [num_input][max_str_length]. From your code, I assume that maximal length of each individual string is 100 (given char str[100];).
Then, in a for loop, that loops num_input times, you should scan all your strings and place them in the proper places in your 2D array. This way, your input is stored and ready to be checked by an algorithm. I would encourage you to, instead of writing plain algorith inside of main function, create a function that will take an array and it's size as arguments and return true or 1 when given array contains a string that is a "magic square palindrome" or return false / 0 when it's not. If you do that, you can just loop num_input times again and call your function on currently checked array. Each time the fucntion returns true, you output "YES", otherwise "NO"/
If you don't know anything about 2D arrays and/or making functions yourself, I encourage you to either buy a good C book, or simple google some tutorials, because that stuff is pretty basic and fairly easy to understand.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I need to make a code that identifies the longest string of characters that a separated by space. If there are characters of same length, write them both.
Ex:
Input = Java flow car tree
Output = Java flow tree
Her is the code i wrote
#include <stdio.h>
#include <stdlib.h>
int main()
{
char cuv[100], big[100];
int i;
printf("Scrieti cuvintele\n");
gets(cuv);
cuv[0] = big[0];
for(i = 0; cuv[i] = '/0'; i++){
if(cuv[i] > big[i]){
big[i] = cuv[i];
}
}
printf("%s", big);
return 0;
}
The problem is i dont know very well how char works. So i have little clue on what to do. I ask of you on how to use the char set to be able to count strings in a specific way.
Here is a very simple solution. Try to understand the code. Note the code uses some of the functions from #include<string.h>. So, before going through the code please go through string.h header file and understand the standard functions it provides.
Anyways, here is a very basic program,(feel free to modify it to your needs)
#include<stdio.h>
#include<string.h>
#define MAX 256
int main(){
char input[MAX],*tmp=NULL;
char *word_list[MAX],*word=NULL;
int flag[MAX];
int i=0,index=0,m=0,largest_len=0;
//Get Input From User
printf("Enter Input:\n");
fgets(input,MAX,stdin);
//If using fgets then use strchr() to locate '\n' and replace it with '\0'(null terminating char)
if((tmp=strchr(input,'\n')) != NULL){
*tmp='\0';
}
//Use strtok() function to split the sentence/input into words separated by space
//and store them in an array of char pointers(or more like array of strings)
word = strtok(input," ");
word_list[index] = word;
index++;
while(word != NULL && i<MAX){
word=strtok(NULL," ");
if(word != NULL){
word_list[index] = word;
index++;
}
}
//find the word with the largest lenght
for(i=0;i<index;i++){
if(strlen(word_list[i]) >= largest_len){
largest_len = strlen(word_list[i]);
}
}
//Then store the index of words which have their lenght equal to the largest lenght
for(i=0;i<index;i++){
if(strlen(word_list[i]) == largest_len){
flag[m] = i;
m++;
}
}
//Print the largest words
m=0;
printf("Largest Word('s):");
for(i=0;i<index;i++){
if(flag[m] == i){
printf("%s ",word_list[i]);
m++;
}
}
return 0;
}
The code you've posted doesn't seem to even come close to what you're trying to do -- so much so that it's really not salvageable towards a solution.
That said, think about your "large" (complete) problem as a series of smaller problems instead; each smaller problem is easier to solve than the single larger problem. Your problems seem to be:
1) Input your raw data.
2) Split your raw data into words. You could manually walk through your data looking for spaces and doing what you feel appropriate when you find them, or you could figure out how to use strtok() to parse data for you. Given where you are with your language understanding, doing it manually is probably a better learning experience.
3) Determine the length of the largest word in your collection.
4) Go through your entire collection and output each word whose length is equal to that largest length.
For problem 1, you seem to have this accomplished (but pay attention to the suggestions people have given you about better ways to do it).
Problem 2 might be the most challenging. There are several ways one can go about it. I'm not going to provide a solution, but this snippet is a small start:
for (i = 0; cuv[i] != '\0'; ++i) {
/* do something */
}
Pay attention to the middle term of the for loop; it's not making an assignment to cuv[i] (I point this out because in your posted program, you are making an assignment, which is really not what you intend.) It is comparing the character to the standard C string termination.
You'll need to look at each character as you go through the loop and decide if you are increasing the current word, ending the previous word, starting a new word, or just skipping repetitive whitespace.
You'll need to store a pointer to each word somewhere so that the full set of words will be available to steps 3 and 4.
Note that you could perform step 3 while you're doing this but you should not for now. It would make your program more efficient, but it merges the steps together and while learning, you don't need that.
Problem 3 requires you to be aware that strlen(const char *s) will return the length of s, where s is a properly terminated C string.
To solve this you will simply iterate through your full set of words and inspect the length of each; if the length is greater than the previous maximum you will increase your stored maximum. Something like:
unsigned int maxLength = 0;
for (i = 0; i < numberOfWords; ++i) {
if (strlen(word[i]) > maxLength)
maxLength = strlen(word[i]);
}
Finally, for step 4 you will iterate through your list of words again, deciding which ones to print out. Something like:
for (i = 0; i < numberOfWords; ++i) {
if (strlen(word[i]) == maxLength)
printf("%s\n", word[i]);
}
What am I supposed to do in order to print only the duplicated words in a file. I'm a beginner in C.
Here's my code:
#include <stdio.h>
#define max 100
main(){
FILE *fpointer;
char ch[max],str[max][max];
int i = 0,j = 0,count = 0;
int a,b;
fpointer = fopen("1.txt","r");
if(fpointer == NULL){
printf("Error!");
return 0;
}
while(fscanf(fpointer,"%s",ch)!=EOF){
strcat(str[i++],ch);
strcat(str[i++]," ");
count++;
}
for(a=0;a<count*2;a=a+2){
for(b=0;b<count*2;b=b+2){
if(strcmp(str[a],str[b])==0){
printf("%s\n",str[b]);
}
}
}
fclose(fpointer);
return 0;
}
An example of input is "shine little star shine bright in the dark star"
and the output of this program is "shine shine little star star shine shine bright in the dark star star". Please help me to print
only duplicate words. Tnx
In your inner loop, instead of starting at the beginning of the list, start one element after the current one. That way you're not comparing an element against itself or comparing any two elements twice.
for(a=0;a<count*2;a=a+2){
for(b=a+2;b<count*2;b=b+2){ // b=a+2 instead of b=0
if(strcmp(str[a],str[b])==0){
printf("%s\n",str[b]);
}
}
}
Output:
shine
star
Since you wrote duplicate words, i am guessing the words in the file will be repeated twice only.
So you second nested for loop is starting from the beginning every time, and thats where the problem is. You have to make sure that the word already checked is not iterated over again. For that you can change your second for loop a little
for(a=0;a<count*2;a=a+2){
for(b=a+2;b<count*2;b=b+2){ //notice b=a+2
if(strcmp(str[a],str[b])==0){
printf("%s\n",str[b]);
}
}
}
Note
For cases when the words are repeating more then twice, my suggestion would be to use some hashing technique to store if a word has already occurred or not. And then compare and print accordingly.
You have a couple of problems here.
Go through and write some comments. For example, put these where they belong:
// Open the file
// Read in the strings
// Compare the strings
If you do this you will notice you have some problems. For instance, what is this line for?
strcat(str[i++]," ");
It's not reading in a string. So what is it doing?
In your final loop, you want to compare each string with all the others. So obviously, you start with the first string, and you compare it to all the others:
for (a=1; a<count; a++)
if(strcmp(str[0],str[a])==0)
{
printf("%s\n",str[0]);
break;
}
Now we can compare the first string with each following string and print it out if it is duplicated. The "break" is there so we only print it once.
But this only compares the first string with the others. How do we compare all of them? Another loop, of course.
// Compare each string against all the ones after it
for (target=0; target<count; target++)
for (a=target+1; a<count; a++)
// If the strings match AND they are not both null
// (why print out copies of null strings? - nobody wants that)
if(strcmp(str[target],str[a])==0) && strlen(str[a])
{
// Print it
printf("%s\n",str[target]);
// Why is this here?
strcpy(str[a],"");
for (copies=a+1; copies<count; copies++)
if(strcmp(str[copies],str[target])==0)
strcpy(str[copies],"");
// We got a match, stop checking for this string
break;
}
See how we've got one big loop that steps through each string, and a smaller loop that steps through all the remaining strings (no point in stepping through the ones we already looked at).
Now a question for you: why is "strcpy(str[a],"") and the next for loop in there? What purpose do they serve?
This is one way to do it. Please enable warnings - you left out a library header. I've also checked array limits. You need to find a better way to limit the string input too, than just guess a large array size.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // included header
#define MAX 100
int main(void){ // correct function
FILE *fpointer;
int reported [MAX];
char ch[MAX], str[MAX][MAX];
int index = 0, a;
fpointer = fopen("1.txt","r");
if(fpointer == NULL){
printf("Error!");
return 0;
}
while(fscanf(fpointer,"%s",ch) == 1){ // testing for 1 item read
for(a=0; a<index; a++){
if(strcmp(ch, str[a])==0){
if (reported[a] == 0) // don't report twice
printf("%s ",ch);
reported[a]++;
break;
}
}
if(a >= index) { // check if loop completed
if (index >= MAX) { // check if array is full
printf("\nToo many words read\n");
exit(1);
}
strcpy(str[index], ch); // word was not found
reported[index] = 0;
index++; // keep tabs on array length
}
}
printf("\n",ch);
fclose(fpointer);
return 0;
}
Program output:
shine star
One issue is that you are storing every word, regardless of whether it has already been seen:
while(fscanf(fpointer,"%s",ch)!=EOF){
strcat(str[i++],ch);
strcat(str[i++]," "); // ??? what is this for
count++;
}
Ideally, you'd only like to store each word once, and maintain a count of how often that word appears in the file:
while ( fscanf( fpointer, "%s", ch ) != EOF ) // whitespace is your friend, use it
{
if ( ch_is_not_already_in_str )
{
strcpy( str[count++], ch );
}
else
{
update_count_for_that_string;
}
}
Then at the end, you just loop through ch and print each string that has a count greater than 1.
for ( i = 0; i < count; i++ )
{
if ( str[i]_occurs_more_than_once )
printf( "%s ", str[i] );
}
The bits you need to figure out are ch_is_not_already_in_str, update_count_for_that_string, and str[i]_occurs_more_than_once. How would you go about searching your str array for an occurence of the string in ch? How would you maintain a counter for each string?