in C, is there a function that when giver two strings, will return the substring overlap or size of the overlap? So like something that does:
char s1[5] = {cart};
char s2[4] = {car};
int overlap;
overlap = get_overlap(s1, s2); /*or have overlap be a string if it returns the overlap*.
and then overlap would be 3.
If not, how do i make one that will return the int value of the overlap.
Use strstr. Example from link:
/* strstr example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="This is a simple string";
char * pch;
pch = strstr (str,"simple");
strncpy (pch,"sample",6);
puts (str);
return 0;
}
Output:
This is a sample string
Note:
The entire substring will be matched ; note that strstr does not do partial matches.
char *strstr(const char *str1, const char *str2);
The function strstr() finds the
occurrence of str2 in the str1 and
returns the pointer to occurrence of
str2 in str1. If no match found, then
a null pointer is returned.
Qualification: This function computed overlaps of the type
string1
ng1randomcharacters
In this case, the overlap is 3
// Traverses s1 from left to right and s2 from left to right, looking for overlap
int get_overlap(char *s1, char *s2)
{
int u2 = strlen(s2)-1;
int p1 = strlen(s1)-1;
int p2 = 0;
while( p1>=0 && p2<=u2 )
{
if (s1[p1--] != s2[p2++])
{
--p2; // no overlap, so correct for incremented value
break;
}
}
return(p2);
}
There's no builtin function, but it's pretty simple to write:
size_t overlap(const char *s1, const char *s2)
{
size_t i = 0;
while (s1[i] && s2[i] && s1[i] == s2[i])
i++;
return i;
}
Related
I need to write function which will check if string s2 is reverse substring of string s1, and return 1 if the condition is true. Function should be made using pointer arithmetic.
For example:
char s1[] = "abcdef";
char s2[] = "edc";
Function would return 1 because string s1 contains reverse string s2.
#include <stdio.h>
int reverseSubstring(const char *s1, const char *s2) {
while (*s1 != '\0') {
const char *p = s1;
const char *q = s2;
while (*p++ == *q++)
if (*q == '\0')
return 1;
s1++;
}
return 0;
}
int main() {
char s1[] = "abcdef";
char s2[] = "edc";
printf("%d", reverseSubstring(s1, s2));
return 0;
}
This function does the opposite. It checks if the string is substring and in my case it returns 0. It should return 1. How to modify this to work?
Note: it is not allowed to use functions from the string.h, stdlib.h libraries, nor the sprintf and sscanf functions from the stdio.h library. It is not allowed to create auxiliary strings or strings in function or globally.
Slight modification to parts of your code:
const char *q = s2;
while(*q) q++; // Make q point to end of string
while (*p++ == *--q) // Decrement instead of incrementing
if (q == s2) // If we have traversed complete substring
return 1;
This is most likely good enough for a school task, which this most likely is. But it might be good to know that the operation q-- will invoke undefined behavior for an empty string because it will make q point to the element before the string. That can be easily fixed. Just add if(*s2 == '\0') return 1; in the beginning of the function because an empty string is a substring of every string.
For completeness, here is a full version with some small fixes and optimizations. I also took the liberty of replacing a while loop with the library function strlen even if it was forbidden in the task. After all, the while loop is described above, and strlen is easy to implement on your own.
const char *
reverseSubstring(const char *s1, const char *s2) {
if(*s2 == '\0') return s1;
const char *end = s2 + strlen(s2);
while (*s1 != '\0') {
const char *p = s1;
const char *q = end;
while (*p++ == *--q)) {
if (q == s2) return s1;
}
s1++;
}
return NULL;
}
Note that I changed the return type. It returns NULL if no match is found, but if a match is found, it returns a pointer to the first match. That means it contains more information for free.
i wrote this code without looking on the net and having a look in the builtin.
how can remove that temp variable and write directly in one of the variable passed in strcat12()?
#include <stdio.h>
char temp[]="";
int strlen12(char *str) {
int count = 0;
while(*str) {
count++;
str++;
}
return count;
}
char strcat12(char *str, char *str2) {
int i = 0;
int l = strlen12(str);
while(*str) {
temp[i++] = *str;
str++;
}
while(*str2) {
temp[l++] = *str2;
str2++;
}
}
The code has some errors and some place on which it can comply with standard.
strlen function returns the length of the string. Better would be if you return size_t and parameter is of type const char*.
Now strcat doesn't behave the way you implemented it. What happens then? Standard says
char *strcat(char * restrict s1, const char * restrict s2);
The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1. If copying takes place between objects that overlap, the behavior is undefined.
Returns
The strcat function returns the value of s1.
char * mystrcat(char *dest, const char *src)
{
size_t i=0,j=0;
while( dest[i] ) i++ ;
while( src[j] ) { dest[i+j] = src[j]; j++; }
dest[i+j] = '\0';
return dest;
}
The same way strlen() returns size_t.
size_t strlen(const char *s){
size_t len = 0;
for( ; s[len] ; len++ )
;
return len;
}
Now the problems in your code
char temp[]="" this is an one length string containing only the single character \0.
This is not a good idea to have a function that will fill one of the char array when called with 2 strings. This side effect is not desirable and it is not reusable.
char strcat12(char *str, char *str2) You are supposed to return a char but you returned nothing.
char strcat12(char *str, char *str2) Again why do you want to return a char?
Now if you are using a global variable why do you even need to return anything as far as the code is given. void strcat12(char *str, char *str2) will be ok.
A slightly better idea can be that you will return a char* which will contain the concatenated string. What I mean by this is you will allocate memory and return pointer to that memory and the memory holds concatenated string.
regarding your question: how can remove that temp variable and write directly in one of the variable passed in strcat12()?
to write directly into the parameter 'str', the array pointed to by 'str' must be long enough to hold the contents of both parameters + the terminating NUL byte.
Then the variable temp[] does not need to be referenced.
here is one way to implement the strcat12() function:
char * strcat12(char *dest, const char *src)
{
size_t i;
for (i = 0; dest[i]; i++);
for (size_t j = 0; src[j]; j++)
dest[i+j] = src[j];
dest[i+j] = '\0';
return dest;
}
I need to extract substrings that are between Strings I know.
I have something like char string = "abcdefg";
I know what I need is between "c" and "f", then my return should be "de".
I know the strncpy() function but do not know how to apply it in the middle of a string.
Thank you.
Here's a full, working example:
#include <stdio.h>
#include <string.h>
int main(void) {
char string[] = "abcdefg";
char from[] = "c";
char to[] = "f";
char *first = strstr(string, from);
if (first == NULL) {
first = &string[0];
} else {
first += strlen(from);
}
char *last = strstr(first, to);
if (last == NULL) {
last = &string[strlen(string)];
}
char *sub = calloc(strlen(string) + 1, sizeof(char));
strncpy(sub, first, last - first);
printf("%s\n", sub);
free(sub);
return 0;
}
You can check it at this ideone.
Now, the explanation:
1.
char string[] = "abcdefg";
char from[] = "c";
char to[] = "f";
Declarations of strings: main string to be checked, beginning delimiter, ending delimiter. Note these are arrays as well, so from and to could be, for example, cd and fg, respectively.
2.
char *first = strstr(string, from);
Find occurence of the beginning delimiter in the main string. Note that it finds the first occurence - if you need to find the last one (for example, if you had the string abcabc, and you wanted a substring from the second a), it might need to be different.
3.
if (first == NULL) {
first = &string[0];
} else {
first += strlen(from);
}
Handle situation, in which the first delimiter doesn't appear in the string. In such a case, we will make a substring from the beginning of the entire string. If it does appear, however, we move the pointer by length of from string, as we need to extract the substring beginning after the first delimiter (correction thanks to #dau_sama).
Depending on your specifications, this may or may not be needed, or another result might be expected.
4.
char *last = strstr(first, to);
Find occurence of the ending delimiter in the main string. Note that it finds the first occurence.
As noted by #dau_sama, it's better to search for ending delimiter from the first, not from beginning of the entire string. This prevents situations, in which to would appear earlier than from.
5.
if (last == NULL) {
last = &string[strlen(string)];
}
Handle situation, in which the second delimiter doesn't appear in the string. In such a case, we will make a substring until end of the string, so we get a pointer to the last character.
Again, depending on your specifications, this may or may not be needed, or another result might be expected.
6.
char *sub = calloc(last - first + 1, sizeof(char));
strncpy(sub, first, last - first);
Allocate sufficient memory and extract substring based on pointers found earlier. We copy last - first (length of the substring) characters beginning from first character.
7.
printf("%s\n", sub);
Here's the result.
I hope it does present the problem with enough details. Depending on your exact specifications, you may need to alter this somehow. For example, if you needed to find all substrings, and not just the first one, you may want to make a loop for finding first and last.
TY guys, worked using the form below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *between_substring(char *str, char from, char to){
while(*str && *str != from)
++str;//skip
if(*str == '\0')
return NULL;
else
++str;
char *ret = malloc(strlen(str)+1);
char *p = ret;
while(*str && *str != to){
*p++ = *str++;//To the end if `to` do not exist
}
*p = 0;
return ret;
}
int main (void){
char source[] = "abcdefg";
char *target;
target = between(source, 'c', 'f');
printf("%s", source);
printf("%s", target);
return 0;
}
Since people seemed to not understand my approach in the comments, here's a quick hacked together stub.
const char* string = "abcdefg";
const char* b = "c";
const char* e = "f";
//look for the first pattern
const char* begin = strstr(string, b);
if(!begin)
return NULL;
//look for the end pattern
const char* end = strstr(begin, e);
if(!end)
return NULL;
end -= strlen(e);
char result[MAXLENGTH];
strncpy(result, begin, end-begin);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *between(const char *str, char from, char to){
while(*str && *str != from)
++str;//skip
if(*str == '\0')
return NULL;
else
++str;
char *ret = malloc(strlen(str)+1);
char *p = ret;
while(*str && *str != to){
*p++ = *str++;//To the end if `to` do not exist
}
*p = 0;
return ret;
}
int main(void){
const char* string = "abcdefg";
char *substr = between(string, 'c', 'f');
if(substr!=NULL){
puts(substr);
free(substr);
}
return 0;
}
Is there a proper way of comparing two char-arrays if they aren't equal by length?
How to check which character isn't equal?
strcmp seems to give me only bigger or lesser number, not the position of unequal character.
For example, strings:
/home/jjjj/ and
/home/jjjj/kkkk/asdasd
Should return 12
Using strlen() and strstr() you can achieves this in a two-step approach:
#include <string.h>
#include <stdio.h>
...
char str1[] = "this is a long string";
char str2[] = "long";
{
char * ss = NULL;
char * sg = NULL;
size_t size1 = strlen(str1)
size_t size2 = strlen(str2);
size_t size_ss = 0;
/* step 1: determine which of the two strings tobe compared it the smaller/greater one. */
if (size1 > size2)
{
size_ss = size2;
ss = str2;
sg = str1;
}
else
{
size_ss = size1;
ss = str1;
sg = str2;
}
/* step 2: find out where the smaller string is located in the greater one, if ever... */
{
char * p = strstr(sg, ss);
if (p)
{
printf("'%s' is the same as '%s' from character %zu to character %zu.\n",
sg, ss, p - sg, p - sg + size_ss);
}
else
{
/* printf("The strings are 100%% differently!\n"); */ /* changed as per Jonathan's comment. */
printf("'%s' does not appear in '%s'.\n", ss, sg);
}
}
}
This solution does not take into account that the shorter string could appear more than once in the longer string. It always notifies about the first occurrence.
There isn't a standard C function that returns the first point of discrepancy between two strings.
It wouldn't be hard to create one; take a version of strcmp() from a text book and modify it so that returns the offset of the strings at the point where the result is 'interesting'. If the strings are equal, that will be the offset of the null terminator ('\0'); otherwise, it will be the offset where the two strings are different.
Maybe something like this:
const char* strcmp_plusplus (const char* str1, const char* str2)
{
const char* result = NULL; // return NULL if equal
while(*str1 != '\0')
{
if(*str1 != *str2)
{
result = str1; // point at where in str1 they are different
break;
}
str1++;
str2++;
}
return result;
}
Note that we won't have to check if str2 is \0, because the C standard allows us to read one element beyond an array without invoking undefined behavior. If str2 ends before str1, the function will return a pointer to str1's null termination.
This function attempts to do it all at once. Since a function can only return one value, one of the resulting values (the difference) has to be passed back to the caller via a pointer to it.
#include <stdio.h>
size_t lead_cmp( const char * one, const char * two, int *result);
size_t lead_cmp( const char * one, const char * two, int *result)
{
size_t pos;
for(pos=0; one[pos] && two[pos]; pos++) {
if (one[pos] != two[pos]) break;
}
*result = one[pos] - two[pos];
return pos;
}
int main(int argc, char **argv)
{
size_t len;
int diff;
len = lead_cmp (argv[1], argv[2], &diff );
printf( "Pos=%zu, Rc=%d\n", len, diff);
return 0;
}
Result:
$ ./a.out /home/jjjj/ /home/jjjj/kkkk/
Pos=11, Rc=-107
$
The found position is 11, not 12, since C uses 0-based indexing.
It returns the number of matching characters: the length of the common prefix.
is this the standard code for strstr i made????
char* fstrset(char *s,char *t)
{
int b, i=0,j=0;
while(*(s+i)!='\0')
{
if(*(t+j)=='\0')
break;
else if(*(s+i)==*(t+j))
{
i++;j++;b=1;
}
else
{ i++;b=0;j=0;
}
}
if(b==0)
return((char*)NULL);
else if(b==1)
return(s+i-j);
}
This is all the standard has to say about it:
7.21.5.7 The strstr function
Synopsis
#include <string.h>
char *strstr(const char *s1, const char *s2);
Description
The strstr function locates the first
occurrence in the string pointed to by
s1 of the sequence of characters
(excluding the terminating null
character) in the string pointed to by
s2.
Returns
The strstr function
returns a pointer to the located
string, or a null pointer if the
string is not found. If s2 points to a
string with zero length, the function
returns s1.
So, it looks like you're missing const qualifiers on arguments.
As for style, note that *(ptr+index) can be replaced by ptr[index], and size_t is the best type to use for indexing a pointer.
As for being a common way to implement it, compare with GCC's code:
char *
strstr (const char *s1, const char *s2)
{
const char *p = s1;
const size_t len = strlen (s2);
for (; (p = strchr (p, *s2)) != 0; p++)
{
if (strncmp (p, s2, len) == 0)
return (char *)p;
}
return (0);
}
Your code is buggy. Given:
char *haystack = "fififi-trixabelle";
char *needle = "fifi-trixabelle";
fstrset(haystack, needle) returns incorrectly returns NULL.
Besides the bug mentioned by caf there are others:
1) Uninitialized b. If s points to '\0', closing brace may be reached, omitting any return statements.
2) If characters match up to the end of string pointed to by s there is no check if the string pointed to by t ends too.
What does this do? It looks like gibberish. Why adding pointers, and mixing them with ints? Sorry, but the whole thing doesn't make sense.
And to answer your question, i don't think so. But if you compile it and it runs, then yes.
Okay, your code does make sense when you look at it closer. Yes, it does look like it will compile, if thats what you mean by standard code.
inline char* strstr(char* __s1, const char* __s2)
{
return __builtin_strstr(const_cast<const char*>(__s1), __s2);
}
a quick read through seems to show that the code works (there are probably edge cases that dont work). You tell us, does it work?
But why do it? just call strstr
There is no 'standard code', just the standard result.
It is unlikely that any implementation in a standard C library uses array indexing, so it is unlikely that your code matches any implementation in line-by-line detail.
char* fstrstr(char *s1,char *s2)
{
int i=0,flag=0;
char *s4,*s3;
// s4 for retaining the value of s2
s4 = s2;
while(*s1 != '\0' && *s2 != '\0')
{
if(*s1 == *s2)
{
*(s3+i) = *s1;
s2++;
s1++;
i++;
flag = 1;
}
else
{
i = 0;
s1++;
// Initialize s2 again from its address
s2 = s4;
flag = 0;
}
}
if(flag == 1)
{
while(*s1 != '\0')
{
*(s3+i) = *s1;
i++;
s1++;
}
*(s3+i) = '\0';
}
if(flag == 1)
return (s3);
if(flag==0)
{
*s3 = NULL;
return (s3);
}
}
There is no "standard code", only standard results.
It is unlikely that any implementation in the standard C library will use array indexes, so your code is unlikely to match any implementation in the line implementation.
char *strstr(const char *s1, const char *s2) {
char *a = s1, *b = s2;
for (;;)
if (!*b) return (char *)s1;
else if (!*a) return NULL;
else if (*a++ != *b++) {a = ++s1; b = s2;}
}