I'm trying to find how may times two string matches in c, if we have two or more stars, multiple string combination can be suitable. e.g "abcdb" & "*b*" matches two times. my current code works but it returns four. I don't what I am missing here.
#include <stdio.h>
int nmatch(char *s1, char *s2) {
if (*s1 != '\0' && *s2 != '\0' && *s2 == '*' && (*s2 + 1) != *s1) {
return nmatch(s1 + 1, s2) + 1;
}
if (*s1 == *s2) {
return nmatch(s1 + 1, s2 + 1);
}
if (*s1 == *s2 && *s1 == '\0' && *s2 == '\0') {
return 0;
}
return (1);
}
int main() {
char ap[] = "abcd";
char ab[] = "*b*";
printf("%d", nmatch(ap, ab));
return 0;
}
Your code just does not count the number of different ways s1 matches pattern s2. It does not even return 1 for identical strings.
The first comparison (*s2 + 1) != *s1 is incorrect, you probably meant *(s2 + 1) != *s1 equivalent to s2[1] != *s1, but this fix is not enough to correct the algorithm.
Here is a naive implementation that does:
int nmatch(const char *s1, const char *s2) {
int count;
while (*s2 != '\0' && *s2 != '*' && *s1 == *s2) {
s1++;
s2++;
}
if (*s2 == '\0')
return *s1 == '\0';
if (*s2 != '*')
return 0;
while (*s2 == '*') /* skip all stars */
s2++;
if (*s2 == '\0')
return 1;
for (count = 0;; s1++) {
count += nmatch(s1, s2);
if (*s1 == '\0')
break;
}
return count;
}
I think your algorithm is just wrong. Together with the flawed implementation this will lead no where.
There's the input string and the pattern string. If the first character of the pattern is not a * and is not equal to the first character of the input string, then return 0 (it's a mismatch).
If they're equal, then remove the first character of both the input and the pattern and return the number of matches of the reduced input and pattern.
On the other hand, if the first character of the pattern is a *, then (in a loop) sum the number of matches of the remaining pattern with the complete input string, the input string without the first, then without the second character ... and so on until the input string is empty.
If both input and pattern are empty: return 1. If only one of the strings is empty: return 0.
I implemented it as direct recursive function (for production use that should be changed into an iterative version):
unsigned matches(char const * const input, char const * const pattern) {
if (! *pattern) {
// An empty pattern matches only the empty
// string, nothing else
return (*input) ? 0 : 1;
}
if (*pattern == '*') {
// a wildcard could be zero to any number
// of characters. Sum the number of matches
// for each possibility (excluding the empty
// rest of input for now)
char const * rest = input;
unsigned count = 0;
while (*rest) {
count += matches(rest, pattern + 1);
++rest;
}
// Add matches for the empty rest of input
count += matches(rest, pattern + 1);
return count;
}
if (! *input) {
// A non empty, non wildcard pattern cannot
// match the empty string
return 0;
}
if (*pattern == *input) {
// non wildcard match, count the ways the rest of
// the pattern matches the rest of the input.
return matches(input + 1, pattern + 1);
}
else {
// mismatch!
return 0;
}
}
(Live with tests)
To deal with the combinatory explosion of possible matches when there are multiple adjacent wildcards in the pattern one could remove these from the pattern first.
Related
Here is what I need to do: delete all occurrences of a number that appears most frequently in a given string
Here is what I've done: wrote two functions; the second one extracts all integers from a string into an array, finds the most frequently repeated one, calls the first function to find that number in a string, deletes all its occurrences in a given string
The problem is it works alright when I compile it, but doesn't pass the series of auto-generated tests and displays "access to an uninitialised value" and "memory error" in lines I marked with <------.
I know this is not exactly the "minimum reproducible code" but I'm hoping someone could point out what the problem is, as I run into a lot of similar errors when working with pointers.
char* find_number(char* string,int search)
{
int sign=1;
int number=0,temp=0;
char* p = string;
while(*string != '\0') {<----------
p=string;
if(*string=='-') sign=-1;
else if(*string==' ') {
string++;
continue;
} else if(*string>='0' && *string<='9') {
temp=0;
while(*string != '\0' && *string>='0' && *string<='9') {
temp=temp*10+*string-'0';
string++;
}
number=temp*sign;
if(number==search) {
return p;
}
} else {
sign=1,number=0;
}
string++;
}
return NULL;
}
char* delete_most_frequent(char* string)
{
//writing all integers in a string to an array
char* pointer=string;
char* s = string;
int temp=0, sign = 1,i=0,array[1000],number=0,counters[1001]= {0},n=0;
while (*s != '\0') {<------------
if (*s == '-') sign = -1;<----------
else if (*s >= '0' && *s <='9') {<----------
temp = 0;
while (*s != '\0' && *s >= '0' && *s <= '9') {
temp = temp * 10 + *s - '0';
s++;
}
number=sign*temp;
if(number>=0 && number<=1000) {
array[i]=number;
i++;
}
}
number=0;
sign=1;
s++;
}
n=i;//size of the array
//finding the number that occurs most frequently
int max=0;
for (i=0; i<n; i++) {
counters[array[i]]++;
if(counters[array[i]]>counters[max]) {
max=array[i];
}
}
char* p=find_number(string,max);//pointer to the first digit of wanted number
//deleting the integer
while (*string != '\0') {
if (p != NULL) {
char *beginning = p, *end = p;
while(*end>='0' && *end<='9')
end++;
//while (*beginning++ = *end++);
while(*end != '\0'){
*beginning = *end;
beginning++;
end++;
}
*beginning = '\0';
} else string++;
p=find_number(string,max);
}
return pointer;//pointer to the first character of a string
}
int main()
{
char s[] = "abc 14 0, 389aaa 14! 15 1, 153";
printf("'%s'", delete_most_frequent(s));
return 0;
}
chopping your code down to just what is likely causing the problem, you have pattern that looks like
while(*string != '\0') {
:
while(*string != '\0' ...) {
:
string++;
}
:
string++;
}
so you have two nested while loops, both of which are advancing the pointer looking for a NUL terminator to end the loop. The problem is that if the inner loop gets all the way to the NUL (it might stop earlier, but it might not), then the increment in the outer loop will increment the pointer past the NUL. It will then happily run through (probably invalid) memory looking for another NUL that might not exist. This is a hard one to catch as in most test cases you write, there are likely multiple NULs (soon) after the string, so it will appear to work fine -- you almost have to specifically write a test case to trigger this failure mode to catch this.
One fix would be to check you're not yet at the null before incrementing -- if (*string) string++; instead of just string++;
I am blocked at solving a problem in the book.
The problem is:
read a word and output the string backwards, and output it backwards,
you should print the palindrome if it is the same as the original.
Also, do not use a library such as string.h, but include stdio.h
only.
So I created the code below.
#include <stdio.h>
int main()
{
char str[128];
char temp;
int leng = 0;
char a;
scanf("%s", str);
{
a = str;
}
while(str[leng] != '\0')
leng++;
for (int i = 0; i < leng/2; i++)
{
temp = str[i];
str[i] = str[leng - i - 1];
str[leng - i - 1] = temp;
}
printf("%s\n", str);
{
if (a == str)
printf("palindrome\n");
}
return 0;
}
The output in reverse order was easily solved, but I blocked in the process at printing palindrome. I tried to print the palindrome only when the input and output values are the same.
However, if (a == str) I used was a code to compare address values.
Also,I thought that it would be useful to implement strcmp as a loop, but I can not find a way to compare the input value with the output value using strcmp.
Is there a way to compare the input and output values in C? Or is there a way to make palindrome print only under certain circumstances (input = output)?
I am wondering if I can code the input value = output value in C exactly.
Note that my code prints the palindrome when the address values are the same. So I haven't seen yet :(
Here is a loosely written untested code that should resolve your issues.
char str[128];
if( fgets( str, 128, stdin ) )
{
/* I hate this but restriction on string.h
Calculate the size of this string */
size_t s_len = 0;
char *p = str;
for( ; *p && *p != '\n' ; p++ )
s_len++;
/* trim down nextLine characters */
if( p && *p == '\n' )
{
*p = '\0';
}
if( s_len == 0 )
{
/* Should never be the case here */
exit(0);
}
/* This should handle both cases of reversing and pallindrom */
int isPallindrom = 1; /* Lets Say Yes for now*/
for( size_t i = 0, j = s_len-1; i < j ; i ++, j -- )
{
if( str[i] != str[j] )
isPallindrom = 0; // Not a pallindrom
swap( str, i, j); // Write a swap function here
}
/* at this point you should have
1. a reversed string in a
2. based on isPallindrom value a confirmation if it really a pallindrom */
}
There are some fundamental errors in your code for instance
a = str;
if (a == str)
turn on warnings while compilation to catch these well before execution.
edit - swap for you.
void swap( char *s, size_t i, size_t j )
{
char t = s[i];
s[i] = s[j];
s[j] = t;
}
Use this function:
int compare(char *str1, char *str2)
{
while(*str1 && *str2){
if(*str1 == *str2){
str1++;
str2++;
}
else return (*str2 - *str1);
}
if(*str1)
return -1;
if(*str2)
return 1;
return 0;
}
Logic:
Until '\0' is encountered in one of the strings, check the character in either string. If the characters are equal, continue. Otherwise, return a negative number of the character in string1 > string2, or a positive number if the character in string1 < string2.
Once a '\0' is encountered, check if string1 has any more characters. If yes, it is the greater string, hence return a negative number.
If string1 doesn't have any more characters, check string2. If that too has no more characters, return 0. Otherwise return a positive number.
I've been sitting on a code for almost ten days right now.
I am writing a funtion that get two pointers for 2 different strings, and the function need to return 1 if there is the same number of words, or 0 if there isnt.
I am not allowed to use any lib, global or static int etc, no loops, only recursion, not allowed to change the signature of the function.
what I wrote is the delta between the two sentences. First my code calculates the sum of words in the first sentence, when it gets to the '\0' of the first sentence, it starts to work on the second sentence, and substract each time there is a word.
right now the output of my funtion is the delta, I want somehow to tell the function that if the delta ("the return") is 0 return 1, else return 1.
"
int same_num_words(char *s1, char *s2)
{
printf("%s\n", s1);
printf("%s\n", s2);
if(s1[0]=='\0' && s2[0] == '\0')
{
return 0;
}
if (s1[0] == '\0' ) // AFTER first sentence is complete, substract the second sentence count.
{
if(s2[0]!= ' ' && s2[1]== ' ')
{
return same_num_words(s1, s2+1) -1 ;
}
if(s2[0]!= ' ' && s2[1]== '\0')
{
return same_num_words(s1, s2+1)-1;
}
return same_num_words(s1, s2+1);
}
if(s1[0]!='\0') // first sentence
{
if((s1[0]!= ' ' && s1[1]== ' ') || (s1[0]!= ' ' && s1[1]== '\0') ) // first sentence
{
return same_num_words(s1+1, s2)+1;
}
}
return same_num_words(s1+1, s2);
}
"
any help?
Each character is either a letter or delimiter ('\0' or whitespace: space, \n \t, etc)
1 - Any leading whitespace is irrelevant, so skip over those.
2 - If code is at the end of either string, we are done.
3 - Since each string now begins with a letter, see it the next character is also a letter.
int same_num_words(const char *s1, const char *s2) {
// printf("'%s' ", s1);
// printf("'%s'\n", s2);
if (s1[0] == ' ') return same_num_words(s1 + 1, s2);
if (s2[0] == ' ') return same_num_words(s1, s2 + 1);
if (s1[0] == '\0' && s2[0] == '\0') return 1; // same
if (s1[0] == '\0') return 0; // differ
if (s2[0] == '\0') return 0;
// Both s1,s2 begin with a letter (non-delimiter)
// If the next character is also a letter, skip over the current one.
// as code is looking for the end-of-word.
if (!(s1[1] == '\0' || s1[1] == ' ')) return same_num_words(s1+1, s2);
if (!(s2[1] == '\0' || s2[1] == ' ')) return same_num_words(s1, s2+1);
return same_num_words(s1+1, s2+1);
}
Expand s1[0] == ' ' to s1[0] == ' ' || s1[0] == '\t' || ... as needed.
A key change from OP code was skipping leading spaces first as that consumes the string's leading and trailing spaces.
For fun, a cleaner looking implementation with typically fewer recursions.
int same_num_words(const char *s1, const char *s2) {
int sp1 = *s1 == ' ';
int sp2 = *s2 == ' ';
if (sp1 | sp2) return same_num_words(s1 + sp1, s2 + sp2);
int nc1 = *s1 == '\0';
int nc2 = *s2 == '\0';
if (nc1 | nc2) return nc1 & nc2;
// Both s1,s2 begin with a letter (non-delimiter)
// How about the next character?
int nxt_let1 = !(s1[1] == '\0' || s1[1] == ' ');
int nxt_let2 = !(s2[1] == '\0' || s2[1] == ' ');
if (nxt_let1 | nxt_let2) return same_num_words(s1 + nxt_let1, s2 + nxt_let2);
return same_num_words(s1 + 1, s2 + 1);
}
This solution obeys the letter of the rules (although I did add some const). It overloads the meaning of same_num_words to return the number of words in the string if either of the arguments is NULL. The second argument is NULL if the previous character read (if any) was space, and the first argument NULL if we've just read a word character.
int same_num_words(const char *s1, const char *s2) {
if (!s1 || !s2) {
const char *s = s1 ? s1 : s2;
if (*s == '\0') return !s1;
if (*s == ' ') return !s1 + same_num_words(s + 1, 0);
return same_num_words(0, s + 1);
}
return same_num_words(s1, 0) == same_num_words(s2, 0);
}
Here's some unit tests to check the implementation.
#include <assert.h>
#include <stdio.h>
int main(int argc, char **argv) {
struct {
const char *word1;
const char *word2;
int want;
} cases[] = {
{"This is a test", "one two three four", 1},
{"", "", 1},
{"one", "", 0},
{" one two three ", "one two three", 1},
{"one two three ", "one two three", 1},
{"one two three ", "one two three four", 0},
{" ", "", 1},
};
int failed = 0;
for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
int got = same_num_words(cases[i].word1, cases[i].word2);
if (got != cases[i].want) {
printf("same_num_words('%s', '%s') = %d, want %d\n", cases[i].word1, cases[i].word2, got, cases[i].want);
failed = 1;
}
got = same_num_words(cases[i].word2, cases[i].word1);
if (got != cases[i].want) {
printf("same_num_words('%s', '%s') = %d, want %d\n", cases[i].word2, cases[i].word1, got, cases[i].want);
failed = 1;
}
}
assert(!failed);
return 0;
}
Try this:
int check_words(char *str1, char*str2) {
if (!str1 && !str2) {
return 1;
}
if (!str1 || !str2) {
return 0;
}
if (*str1=='\0' && *str2=='\0') {
return 1;
}
if((*str1==' ' || *str1=='\t') && (!(*str2==' ' || *str2=='\t' || *str2=='\0')))
return check_words(str2+1, str1);
if((*str2==' ' || *str2=='\t') && (!(*str1==' ' || *str1=='\t' || *str1=='\0')))
return check_words(str1+1, str2);
if (*str1=='\0' && (*str2==' ' || *str2=='\t')) {
return check_words(str1, str2+1);
}
if (*str2=='\0' && (*str1==' ' || *str1=='\t')) {
return check_words(str2, str1+1);
}
if (*str1!='\0' && *str2!='\0') {
return check_words(str1+1, str2+1);
}
else {
return 0;
}
}
I need to develop a function that goes through a character string and detects letters (lower and upper cases), digits 0-9 and spaces ' '. If the functions finds only valid characters (the characters listed before) it returns 1 otherwise(if the string has characters like !,&,/,£, etc.) it returns 0. I am aware of a function that finds characters and digits which is isalnum().That is not helpful to find spaces. Does anyone can provide inbuilt or manual function which can detect characters,digits and spaces all together.
I've developed mine as under but function does not detect invalid character !,&,/,£ etc. in middle of the string and therefore it does not return the value I expect.
for (i=0; i<strlen(str); i++) {
if ((str[i]>='A' && str[i]<='Z') || str[i] == ' ' || (str[i]>='a' && str[i]<='z') || (str[i]>='0' && str[i]<='9'))
for (i=0; i<strlen(str); i++) {
char *p = str;
while (*p) {
if (isalnum((unsigned char) *p) || *p == ' ') {
res =1;
} else {
res = 0;
}
p++;
}
}
You can make the code more succinct:
int Validate_Alphanumeric(char *str)
{
unsigned char *ptr = (unsigned char *)str;
unsigned char uc;
while ((uc = *ptr++) != '\0')
{
if (!isalnum(uc) && uc != ' ')
return 0;
}
return 1;
}
Amongst other things, this avoids reevaluating strlen(str) on each iteration of the loop; that nominally makes the algorithm quadratic as strlen() is an O(N) operation and you would do it N times, for O(N2) in total. Either cache the result of strlen(str) in a variable or don't use it at all. Using strlen(str) requires the entire string to be scanned; the code above will stop at the first punctuation or other verboten character without scanning the whole string (but the worst case performance, for valid strings, is O(N)).
I came up with a function that goes through the string and that is able to return 0 if an invalid character (ex. $&$&&(%$(=()/)&)/) is found.
int Validate_Alphanumeric (char str[]) {
int i;
int res;
int valid=0;
int invalid=0;
const char *p = str;
while (*p) {
if (isalnum((unsigned char) *p) || *p == ' ') {
valid++;
} else {
invalid++;
}
p++;
}
if (invalid==0)
res=1;
else
res=0;
return res;
}
for example, given the string str1 = "120jdvj00ncdnv000ndnv0nvd0nvd0" and the character ch = '0', the output should be 12jdvj00ncdnv000ndnvnvdnvd. That is, the 0 is removed only wherever it occurs singly.
this code is not working
#include<stdio.h>
char remove1(char *,char);
int main()
{
char str[100]="1o00trsg50nf0bx0n0nso0000";
char ch='0';
remove1(str,ch);
printf("%s",str);
return 0;
}
char remove1(char* str,char ch)
{
int j,i;
for(i=0,j=0;i<=strlen(str)-1;i++)
{
if(str[i]!=ch)
{
if(str[i+1]==ch)
continue;
else
str[j++]=str[i];
}
}
str[j]='\0';
}
Your code looks for an occurrence of something other than the character to be removed with "if(str[i]!=ch)", then if the next character is the one to be removed it skips (i.e. does not keep the characters it has just seen), otherwise it copies the current character. So if it sees 'a0' and is looking for '0' it will ignore the 'a'.
What you could do is copy all characters other than the one of interest and set a counter to 0 each time you see one of them (for the number of contiguous character of interest you've seen at this point). When you find the one of interest increment that count. Now whenever you find one that is not of interest, you do nothing if the count is 1 (as this is the single character you want to remove), or put that many instances of the interesting character into str if count > 1.
Ensure you deal with the case of the string ending with a contiguous run of the character to be removed, and you should be fine.
char *remove1(char* str, char ch){
char *d, *s;
for(d = s = str;*s;++s){
if(*s == ch){
if(s[1] == ch)
while(*s == ch)
*d++=*s++;
else
++s;//skip a ch
if(!*s)break;
}
*d++ = *s;
}
*d = '\0';
return str;
}
Code to copy the basic
for(d = s = str;*s;++s){
*d++ = *s;
}
*d = '\0';
Special processing to be added.
for(d = s = str;*s;++s){
if(find a character that is specified){
Copy that in the case of continuously than one character
if one letter then skip
}
*d++ = *s;
}
*d = '\0';
Here is the working code
output is : "1o00trsg5nfbxnnso0000"
#include<stdio.h>
char remove1(char *,char);
int main()
{
char str[100]="1o00trsg50nf0bx0n0nso0000";
char ch='0';
remove1(str,ch);
printf("%s",str);
return 0;
}
char remove1(char* str,char ch)
{
int j,i;
int len = strlen(str);
for(i = 0;i < (len - 1);i++){
if(str[i] == ch){
/* if either of check prev and next character is same then contd. without removal */
if((str[i+1] == ch) || (str[i-1] == ch))
continue;
/* replacing the char and shifting next chars left*/
for(j = i;j < (len - 2);j++) {
str[j] = str[j + 1];
}
/* string length is decrementing due to removal of one char*/
len--;
}
}
str[len] = '\0';
}