comparing strings (from other indices rather than 0) - c

How can one compare a string from the middle (or some other point but not the start) to another string?
like i have a string
str1[]="I am genius";
now if i want to find a word in it how should i compare it with the word? for example the word is am.
Here is what i did.Its a bit stupid but works perfectly :D
#include<stdio.h>
#include<string.h>
void print( char string[]);
int main()
{
int i;
char string1[20];
printf("Enter a string:");
gets(string1);
print(string1);
return 0;
getch();
}
void print(char string[])
{
int i,word=1,sum=0,x;
for(i=0; ;i++)
{
sum++;
if(string[i]==' ')
{
printf("Word#%d:%d\n",word,sum-1);
sum=0;
word++;
}/* if ends */
if(string[i]=='\0')
{ // program sai kaam karnay k liye ye code yahan bhi paste hona chahyey
printf("Word#%d:%d\n",word,sum-1);
sum=0;
word++;
break;
}
}/* for ends*/
}

Use strncmp():
strncmp( whereToFind + offsetToStartAt, patternToFind, patternLength );

If you wish to find a substring in a string, use the function strstr():
char *p = strstr(str1, "am");
if (p != NULL)
{
// p now points to start of substring
printf("found substring\n");
}
else
{
printf("substring not found\n");
}

If you want to compare the remainder of string s1 starting at index i1 to the remainder of string s2 starting at i2, it's very easy:
result = strcmp(s1+i1, s2+i2);
If you want to see if the substring of s1 beginning at i1 matches the string s2, try:
result = strcmp(s1+i1, s2);
or:
result = strncmp(s1+i1, s2, strlen(s2));
depending on whether you want the whole remainder of s1 to match or just the portion equal in length to s2 to match (i.e whether s1 contains s2 as a substring beginning at position i1.
If you want to search for a substring, use strstr.

Since this is homework I am assuming you can't use standard functions, so I can think of two solutions:
Split all of the words into a link
list, then just compare each string
until you find your word.
Just use a for loop, start at the
beginning, and you can use [] to
help jump through the string, so
instr[3] would be the fourth
character, as the index is
zero-based. Then you just see if you are at your word yet.
There are optimizations you can do with (2), but I am not trying to do your homework for you. :)

One option you be to use
size_t strspn( char *s1, const char *s2) /* from #include <string.h> */
*returns the length of the longest substring of s1 that begins at the start of s1 and consists only of the characters found in s2.
If it returns ZERO than there is no substring.

You can use parse the string into words and store them in new char arrays/pointers.
Or
Suppose the string you want to find is "am" stored in ptr *str2.
You start comparison using the index[] from str1 till you find a matching char for index 0 from str2
Once you find a match increment both pointers till you reach end of str2 to compare entire string.
If there is no match then continue to find char at index 0 in str2 in str1 from the place where you entered step 2.
Alternatively
You have to use a two dimensinal array.
char str[3][10] = { "i","am","2-darray"};
Here str[1] will contain "am". Thats assuming you want to get indvidual words of a string.
Edit: Removed the point diverting from OP

Related

C: Replacing a substring within a string using loops

I am struggling with the concept of replacing substrings within strings. This particular exercise does not want you to use built in functions from <string.h> or <strings.h>.
Given the string made up of two lines below:
"Mr. Fay, is this going to be a battle of wits?"
"If it is," was the indifferent retort, "you have come unarmed!"
I have to replace a substring with another string.
This is what I have so far, and I'm having trouble copying the substring to a new array, and replacing the substring with the new string:
#include <stdio.h>
#include <string.h>
int dynamic();
int main()
{
char str[]="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";
int i, j=0, k=0, l=0, n=0;
unsigned int e = n-2;
char data[150];
char newData[150];
char newStr[150];
printf("Give me a substring from the string");
gets(data);
printf("Give me a substring to replace it with");
gets(newData);
dynamic();
for (i=0; str[i] != '\0'; i++)
{
if (str[i] != data[j])
{
newStr[l] = str[i];
l++;
}
else if ((str[i+e] == data[j+e]) && (j<n))
{
newStr[l] = newData[j];
j++;
l++;
e--;
}
else if ((str[i+e] == data[j+e]) && (j>=n))
{
j++;
e--;
}
else
{
newStr[l] = str[i];
l++;
}
}
printf("original string is-");
for (k=0; k<n; k++)
printf("%c",str[k]);
printf("\n");
printf("modified string is-");
for(k=0; k<n; k++)
printf("%c",newStr[k]);
printf("\n");
}
int dynamic()
{
char str[]="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";
int i, n=0;
for (i=0; str[i] != '\0'; i++)
{
n++;
}
printf("the number of characters is %d\n",n);
return (n);
}
I tried your problem and got output for my code. Here is the code-
EDIT- THIS IS THE EDITED MAIN CODE
#include <stdio.h>
#include <string.h>
int var(char *); //function declaration. I am telling CPU that I will be using this function in the later stage with one argument of type char *
int main() //main function
{
char *str="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";
int i,j=0,k=0,l=0;
char data[] = "indifferent";
char newData[] = "nonchalant";
char newStr[150];
//here 'n' is returned from the 'var' function and is received in form of r,r1,r2,r3.
int r=var(str); //getting the length of str from the function 'var' and storing in 'r'
int r1=var(data); //getting the length of data from the function 'var' and storing in 'r1'
int r2=var(newData); //getting the length of newData from the function and storing in 'r2'
unsigned int e=r1-2; //r1-2 because r1 is the data to be replaced. and string index starts from 0. Here r1 is of length 12. but we dont need to check last
//character because it is null character and the index starts from 0. not from 1. so, it is 0 to 11 and 11th is '\0'. so "12-"2"=10" characters to be compared.
for(i=0;str[i]!='\0';i++)
{
if(str[i]!=data[j])
{
newStr[l]=str[i];
l++;
}
else if((str[i+e]==data[j+e]) && (j<r2))
{
newStr[l]=newData[j];
j++;
l++;
e--;
}
else if((str[i+e]==data[j+e]) && (j>=r2))
{
j++;
e--;
}
else
{
newStr[l]=str[i];
l++;
}
}
int r3=var(newStr); //getting the length of str from the function and storing in 'r'
printf("original string is-");
for(k=0;k<r;k++)
printf("%c",str[k]);
printf("\n");
printf("modified string is-");
for(k=0;k<r3;k++)
printf("%c",newStr[k]);
printf("\n");
} // end of main function
// Below is the new function called 'var' to get the character length
//'var' is the function name and it has one parameter. I am returning integer. so, it is int var.
int var(char *stri)//common function to get length of strings and substrings
{
int i,n=0;
for(i=0;stri[i]!='\0';i++)
{
n++; //n holds the length of a string.
}
// printf("the number of characters is %d\n",n);
return (n); //returning this 'n' wherever the function is called.
}
Let me explain few parts of the code-
I have used unsigned int e, because I don't want 'e' to go negative.(I will explain more about this later).
In the first for loop, I am checking whether my string has reached the end.
In first 'IF' condn, I am checking whether the first character of string is NOT-EQUAL to the first character of the word which needs to be replaced. If condition satisfies, print regularly thr original string.
ELSE IF, i.e(first character of string is EQUAL to the first character of the word)then check the next few characters to make sure that the word matches. Here, I used 'e' because it will check the condition for str[i+e] and data[i+e]. example- ai notequalto ae. If I had not used 'e'in code,... after checking the first character itself, newdata would have been printed in newstr. I used 'e'=5 because the probabilty of 1st letter and 5th letter being the same in data and the str is less. You can use 'e'=4 also. No rule that you have to use 'e'=5 only.
Now, I am decrementing 'e' and checking whether the letters in the string is same or no. I can't increment because, there is a certain limit of size of a string. As, I used unsigned int, 'e' won't go down below 0.
ELSE, (this means that only first letter is matching, the 5th letter of str and data are not matching), print the str in newstr.
In the last FOR loop, I have used k<114 because, that much characters are there in the string. (You can write a code to find how many characters are there in a string. No need to manually count).
And lastly, I have used conditions (j<10) and (j>=10) along with ELSE-IF condition because, in first ELSE-IF, the new data is ofsize 10. So, even if the word to be replaced is more than 10,say 12 for example. I don't need the extra 2 bits to be stored in new data. So, if the size is more than 10, just bypass that in the next ELSE-IF condition. Note that this 10 is the size of new word. So, it varies if your word is smaller or bigger. And , in second ELSE-IF, I am not incrementing 'l'(l++) because, here, I am not putting anything in newstr. I am just bypassing it. So, I didn't increment.
I tried my best to put the code in words. If you have any doubt, you can ask again. I will be glad to help. And this code is NOT OPTIMAL. The numerical values used varies with the words/strings you use. Ofcourse, I can write a generalized code for that(to fetch the numerical values automatically from the strings). But, I didn't write that code here. This code works for your problem. You can change few variables like 'e' and ELSE-IF part and try to understand how the code works. Play with it.
EDIT-
include
int main()
{
char str[]="\n\"Mr. Fay, is this going to be a battle of wits?\" \n\"If it is,\" was the indifferent retort, \"you have come unarmed!\"";// I took this as string. The string which u need to calculate the length, You have to pass that as the function parameter.
int i,n=0;
for(i=0;str[i]!='\0';i++)
{
n++;
}
printf("the number of characters is %d\n",n);
return (n);
}// If you execute this as a separate program, you will get the number of characters in the string. Basically, you just have to modify this code to act as a separate function and when calling the function, you have to pass correct arguments.
//Use Pointers in the function to pass arguments.

Delete a char in string?

I tried searching for it on google and could not find a simple answer, most of the questions were asking to delete all occurrences of that char from the string and what not.
My pseudo code:
for (e=0;e<length of string;e++){
if (string[e] is not a number/alphabet){
#delete it
}
}
Is there a simple built in way of doing this?
Also another question, I need to do if not isalnum(string[e]), how would I go about doing so?
is it if !(isalnum(string[e])) or is it if (isalnum(string[e]))!=0?
Typically you would build up a second array and copy the valid symbols to that one.
Deleting numbers inside arrays is only possible if you move all trailing numbers down one step, which is very inefficient. If you need a container class where you can easily delete and add items in the middle, you should be using a linked list.
You can treat the return value of isalnum as bool type. Thus either
if ( !isalnum(string[e]) )
or
if ( isalnum(string[e]) !=0 )
are fine and completely equivalent.
You can filter out characters from a string in-place by keeping two indices. That works, because the string can only get shorter and the new string will fit into the old memory. Here's how with two pointers:
int str_alnum(char *str)
{
char *p, *q;
p = q = str;
while (*p) {
if (isalnum(*p)) *q++ = *p;
p++;
}
*q = '\0';
return q - str;
}
p walks the original string, q walks the new string, possibly trailing after p. q - str is the length of the new string, which might be handy as return value.
Note that you have to pass a string that can be modified, i.e. a char array, not a constant string literal.
This is one way to do it if you are using ASCII formatted characters.
char a[256]; // Some string
char destination[256];
char * pos = destination;
for(unigned int i=0;i>strlen(a)-1;++i)
{
if(((a[i]>='A'&& a[i]<='Z') || (a[i]>='a'&& a[i]<='z') || (a[i]>='1'&& a[i]<='9')))
*pos = a[i]; //replaces letter with a whitespace
++pos;
}
*pos = '\0';
Basically what it does it it converts the letter to the corrosponding intenger and then it checks its within the range that represents the letters between A-Z, a-z and 1-9.

Function that finds whether 2 string are made from same words

I need to create a function in C, which finds out if 2 strings are made from same words. As can be seen in current code, I loaded each string in separate array. I made it that in the array there are words, all in lower case letters with just 1 space between each word and without all non-alpha characters. I though, that I could just sort the string and call strcmp on them, but it can't be done so, because of the reason, that there can be strings such as "dog dog dog cat" and "dog cat" , these strings are from same words, so the function should return 1, but it wouldnt if just sorted and used strcmp. So i though, I could merge all duplicated words in 1 and then sort and strcmp, but there is still one problem, that when there would be words such as "dog" and "god" , these are 2 different words, but the function would still take them as same after sorting.
"dog dog dog cat" "dog cat" - same words
"HI HeLLO!!'" "hi,,,hello hi" - same words
I would be very thankful for any help. I really don't know how to create it, I sat at it for quite some time and still can't figure it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int sameWords( const char * a, const char * b)
{
char * array1=NULL;
char * array2=NULL;
int length1=0, length2=0, i=0, j=0;
while(a[i])
{
if(i>=length1)
{
length1+=250;
array1=(char*)malloc(length1*sizeof(char));
}
if(isspace(a[i]) && !isspace(a[i-1]))
{
array1[i]=a[i];
}
if(isalpha(a[i]))
{
array1[i]=tolower(a[i]);
}
i++;
}
while(b[j])
{
if(j>=length2)
{
length2+=250;
array2=(char*)malloc(length2*sizeof(char));
}
if(isspace(b[j]) && !isspace(b[j-1]))
{
array2[j]=b[j];
}
if(isalpha(b[j]))
{
array2[j]=tolower(b[j]);
}
j++;
}
}
int main()
{
sameWords("This' is string !!! ", "THIS stRing is !! string ");
return 0;
}
You have already learned two ways to go about your problem. The complicated one is to split each of the strings into words, sort them and then weed out duplicates, which is easy in a sorted array. The easier one is to split the first string into words, search for each word in the second. Then do the same the other way round: split the second and check for words in the first.
Both approaches require that you split the strings. That's also where you seem to have problems in your code. (You've got the basic idea to look at word boundaries, but you don't seem to know how to store the words.)
The basic question is: How are you going to represent the words, i.e. the substrings of a C string? There are various ways. You could use pointers into the string together with a string length or you could copy them into another buffer.
Here is a sloution that splits the string a into words and then checks whether each word can be found in b:
/*
* Return 1 if all words in a can be found in b,
* return 0 otherwise.
*/
int split_and_check(const char *a, const char *b)
{
int begin = -1; /* marker for beginning of word */
char word[80]; /* temporary buffer for current word */
int prev = 0; /* previously read char to detect word bounaries */
int len; /* current length of word */
int i;
i = 0;
while (1) {
if (isalpha(a[i])) {
if (!isalpha(prev)) {
begin = i;
len = 0;
}
if (len < 80) word[len++] = a[i];
} else {
if (len > 0) {
word[len] = '\0'; /* manually null-terminate word */
if (strstr(b, word) == NULL) {
/* fail on string mismatch */
return 0;
}
len = 0; /* reset word-length counter */
}
}
if (a[i] == '\0') break; /* check end here to catch last word */
prev = a[i++];
}
return 1;
}
The current word is stored in the local char buffer word and has the length len. Note how the zero end marker '\0' is added to word manually before searching b for word: The library function strstr looks for a string in another one. Both strings must be zero-terminated.
This is only one half of the solution. You must check the strings the other way round:
int same_words(const char *a, const char *b)
{
if (split_and_check(a, b) == 0) return 0;
if (split_and_check(b, a) == 0) return 0;
return 1;
}
This is not yet the exact solution to your problem, because the string matching is done case-sensitively. I've skipped this part, because it was easier that way: strstr is case sensitive and I don't know of any variants that ignore the case.
You are returning nothing from your function sameWords whose return type is int.
I don't pretend to be awarded as the answer, but I would take a look at regular expressions too for this kind of things.
Does C or C++ have a standard regex library?
It would take minutes to solve it, you split the string with regex, lowercase-it, and then iterate to look after common words.
What I would do to solve this problem is create a data structure like a tree into which you can insert words. The insert function would do nothing if the word is already there, otherwise, it would convert it to lowercase and insert it in the tree. Then you could simply convert both strings to these types of trees and compare the trees.
Another way to do this is in bash. While this is probably not allowed for you assignment, if you understand how and why it works, you should be able to code something up that mimics it:
# string1 and string2 are simply strings with spaces separating words
s1="dog dog dog cat"
s2="cat dog"
# Convert to arrays
a1=( $(printf "%s\n" ${s1} | sort | uniq ) )
a2=( $(printf "%s\n" ${s2} | sort | uniq ) )
# Compare the result
if [ "${a1[*]}" == "${a2[*]}" ] ; then
echo "Same"
fi

printf() isn't being executed

I wanted to write a program which counts the occurrences of each letter in a string, then prints one of each letter followed by the count for that letter.
For example:
aabbcccd -
Has 2 a, 2 b, 3 c, and 1 d
So I'd like to convert and print this as:
a2b2c3d1
I wrote code (see below) to perform this count/conversion but for some reason I'm not seeing any output.
#include<stdio.h>
main()
{
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
type=*cp;
cp++;
count=cp;
int c;
for(c=1;*cp==type;c++,cp++);
*count='0'+c;
}
count++;
*count='\0';
printf("%s",array);
}
Can anyone help me understand why I'm not seeing any output from printf()?
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
*cp is a pointer it's pointing to the address of the start of the array, it will never be == to a char '\0' so it can't leave the loop.
You need to deference the pointer to get what it's pointing at:
while(*cp != '\0') {
...
Also, you have a ; after your for loop, skipping the contents of it:
for(c=1;*cp==type;c++,cp++); <-- this ; makes it not execute the code beneath it
After fixing both of those problems the code produces an output:
mike#linux-4puc:~> ./a.out
a1b1c2cd
Not the one you wanted yet, but that fixes your problems with "printf not functional"
Incidentally, this code has a few other major problems:
You try to write past the end of the string if the last character appears once (you write a '1' where the trailing '\0' was, and a '\0' one character beyond that.
Your code doesn't work if a character appears more than 9 times ('0' + 10 is ':').
Your code doesn't work if a character appears more than 2 times ("dddd" doesn't become "d4"; it becomes "d4dd").
Probably line-buffering. Add a \n to your printf() formatting string. Also your code is very scary, what happens if there are more than 9 of the same character in a row?
1) error correction
while(*cp!='\0'){
and not
while(cp!='\0'){
2) advice
do not use array[] to put in your result user another array to put in your rusel it's more proper and eay
I tried to solve your question quickly and this is my code:
#include <stdio.h>
#define SIZE 255
int main()
{
char input[SIZE] = "aabbcccd";/*input string*/
char output[SIZE]={'\0'};/*where output string is stored*/
char seen[SIZE]={'\0'};/*store all chars already counted*/
char *ip = input;/*input pointer=ip*/
char *op = output;/*output pointer = op*/
char *sp = seen;/*seen pointer=sp*/
char c,count;
int i,j,done;
i=0;
while(i<SIZE && input[i]!='\0')
{
c=input[i];
//don't count if already searched:
done=0;
j=0;
while(j<SIZE)
{
if(c==seen[j])
{
done=1;
break;
}
j++;
}
if(done==0)
{//if i never searched char 'c':
*sp=c;
sp++;
*sp='\0';
//count how many "c" there are into input array:
count = '0';
j=0;
while(j<SIZE)
{
if(ip[j]==c)
{
count++;
}
j++;
}
*op=c;
op++;
*op=count;
op++;
}
i++;
}
*op='\0';
printf("input: %s\n",input);
printf("output: %s\n",output);
return 0;
}
It's not a good code for several reasons(I don't check arrays size writing new elements, I could stop searches at first empty item, and so on...) but you could think about it as a "start point" and improve it. You could take a look at standard library to copy substring elements and so on(i.e. strncpy).

C: extract numbers from a string

I have a bunch of strings structured like this one
Trim(2714,8256)++Trim(10056,26448)++Trim(28248,49165)
and what I want to do is to save all the numbers into an array (for the sake of this answer let's say I want to save the numbers of just one string).
My plan was to find the the position of the first digit of every number and just read the number with sscanf, but as much as I've thought about it, I couldn't find a proper way to do so. I've read a lot about strstr, but it is used to search for a string into another string, so I should search for the exact number or do 10 cases to cover from 0 to 9.
Thanks in advance for your support!
You could try something like this:
Walk the string until you find the first digit (use isdigit)
Use strtoul to extract the number starting at that position
strtoul returns the number
the second argument (endptr) points to the next character in the string, following the extracted number
Rinse, repeat
Alternatively you could tokenize the string (using "(,+)") and try to strtoul everything.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int arr[10], idx=0, d, l=0;
char *p, *str = "Trim(2714,8256)++Trim(10056,26448)++Trim(28248,49165)";
for (p = str; *p != 0; p+=l) {
l = 1;
if (isdigit(*p)){
sscanf(p, "%d%n", &d, &l);
arr[idx++] = d;
}
}
for (l=0; l<idx; l++) {
printf("%d\n", arr[l]);
}
return 0;
}
You can also try using YACC or Lex, which will format your string as you want.
Here is how I would think about the code:
start loop over source array characters
if the character in the current position (of the source array) is a digit
copy it to the destination array (in the current position of the destination array)
move to the next position in the destination array
move to the next position in the source array
if the end of the source string is reached, exit loop
make sure that the destination string is terminated properly (i.e. by '\0')
Note that we are counting with two different counters one for the source array which will increment with every loop iteration and the other for the destination array and will only increment if a digit is found
checking of a character is a digit or not can be done using the function "isdigit()" but it will require the header file ctype.h
Another way to check if the character is a digit is by checking its value in reference to the ASCII table
character '0' equals 48 and character '9' equals 57. So if the character is within that range it is a digit, other wise it is a character. You can actually compare directly with the characters.
if (character >= '0' && character =< '9') printf("%c is a digit", character);
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int array[8], count=0, data;
const char *s = "Trim(+2714,8256)++Trim(10056,26448)++Trim(28248,49165)";
char *p;
while(*s) {
if(isdigit(*s) || *s=='-' && isdigit(s[1])){
data = strtol(s, &p, 10);
s = p;
array[count++] = data;
} else
++s;
}
{//test print
int i;
for(i=0;i<count;++i)
printf("%d\n", array[i]);
}
return 0;
}

Resources