Related
My code:
What I'm trying to do is to input two strings, then return the longest one. If they're the same length then return NULL. Now, the code is just outputting gibberish and I cannot find out why. The function returns a pointer to the first character of the largest string. Then it goes through the while loop, and I'm trying to dereference the pointer and print out its value.
Note: I'm revising for an exam and we have to use only pointers and not treat strings as arrays.
#include<stdio.h>
char* string_ln(char*, char*);
int main() {
char str1[20];
char str2[20];
char* length;
scanf("%s%s", str1, str2);
length = string_ln(str1, str2);
while (length != '\0') {
printf("%c", *length);
length++;
}
}
char* string_ln(char*p1, char*p2) {
int count1 = 0;
while (*p1 != '\0') {
count1++;
p1++;
}
int count2 = 0;
while (*p2 != '\0') {
count2++;
p2++;
}
if (count1 > count2) {
return p1;
}
else if (count2 > count1) {
return p2;
}
else {
return NULL;
}
}
In writing string_ln you iterate over both strings completely to find their lengths, and then compare those numbers. This can work, but you don't actually need to do this. You only need to know which is longer. It doesn't matter how much longer the longer string is.
char *string_ln(char *str1, char *str2) {
char *iter1, *iter2;
for (iter1 = str1, iter2 = str2;
*iter1 && *iter2;
iter1++, iter2++);
if (!(*iter1 || *iter2)) {
return NULL;
}
else if (*iter1) {
return str1;
}
else {
return str2;
}
}
We simply need to iterate over both strings, until at least one hits a NULL character. Once we get to that point, we can test to see which iterator is NULL. If it's both of them, then they're the same length. If the first iterator is not NULL, then the first string is longer. Otherwise, the second string is longer.
The benefit to this approach is that we avoid unnecessary work, and make it much quicker to compare strings of very different lengths.
There are a few problems here. First, you're modifying p1 and p2 in the function, so you won't actually return a pointer to the beginning of the largest string, but to its end. One way to avoid this is to iterate over copies of p1 and p2:
char* string_ln(char*p1, char*p2)
{
char* tmp1 = p1;
int count1 = 0;
while (*tmp1 != '\0') {
count1++;
tmp1++;
}
char* tmp2 = p2;
int count2 = 0;
while (*tmp2 != '\0') {
count2++;
tmp2++;
}
if(count1>count2){
return p1;
}
else if(count2>count1){
return p2;
}
else{
return NULL;
}
}
Second, in your main, you're using the %c format string, which works for a single char, not a whole string. Since you have a string anyway, you can avoid a format string and just print it directly. Also, note that you should explicitly check for NULLs:
int main() {
char str1[20];
char str2[20];
char* longest;
scanf("%s%s", str1, str2);
longest = string_ln(str1, str2);
if (longest) {
printf(longest);
} else {
printf("They are the same length");
}
}
I think you're missing to dereference the pointer. Instead of
while(length!='\0')
you'd need
while(*length!='\0')
That said, in the called function, you're reuring pointers after the increment, i.e., the returned pointers do not point to the start of the string anymore. You need to ensure that you return pointers which points to the beginning of the string. You can change your code to
int count1 = 0;
while (p1[count1] != '\0') {
count1++;
}
int count2 = 0;
while (p2[count2] != '\0') {
count2++;
}
so that p1 and p2 does not change.
For starters the function should be declared like
char * string_ln( const char *, const char * );
because the passed strings are not being changed within the function.
You are returning from the function the already modified pointer p1 or p2 that is being changed in one of the while loops
while (*p1 != '\0') {
count1++;
p1++;
}
while (*p2 != '\0') {
count2++;
p2++;
}
So the returned pointer points to the terminating zero '\0' of a string.
Moreover in main before this while loop
length = string_ln(str1, str2);
while(length!='\0'){
printf("%c", *length);
length++;
}
you are not checking whether the pointer length is equal to NULL. As a result the program can invoke undefined behavior.
The function itself can be defined the following way using only pointers.
char * string_ln( const char *p1, const char *p2 )
{
const char *s1 = p1;
const char *s2 = p2;
while ( *s1 != '\0' && *s2 != '\0' )
{
++s1;
++s2;
}
if ( *s1 == *s2 )
{
return NULL;
}
else if ( *s1 == '\0' )
{
return ( char * )p2;
}
else
{
return ( char * )p1;
}
}
and in main you need to write
char *length = string_ln( str1, str2 );
if ( length != NULL )
{
while ( *length )
printf( "%c", *length++ );
}
Pay attention to that the return type of the function is char * instead of const char *. It is because in C there is no function overloading and the returned pointer can point to a constant string or to a non-constant string. It is a general convention in C for declaring string functions.
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;
}
I am trying to implement a strnstr function into C (strstr but it checks the length), for some reason it doesn't work (output is always no):
#include <stdio.h>
char *searchingFor = "stackdummy";
char *in = "la da\ndoo a da\nnow here comes the stack\nok there it was.\n";
char *strnstr(char *s1, char *s2, int length) {
if(s1 == NULL || s2 == NULL) return NULL;
printf("searching \n\n\"%s\"\n for %.*s\n", s1, length, s2);
char *ss1 = malloc(strlen(s1) + 1);
strcpy(ss1, s1);
char *ss2 = malloc(length + 1);
strncpy(ss2, s2, length);
char *result = strstr(ss1, ss2);
free(ss1);
free(ss2);
return result;
}
int main(void) {
printf("found: %s\n", strnstr(in, searchingFor, 5) ? "yes" : "no");
printf("found: %s\n", strnstr(in, searchingFor, 5) ? "yes" : "no");
printf("found: %s\n", strnstr(in, searchingFor, 5) ? "yes" : "no");
return 0;
}
The implementation provided by Chris Dodd has the following disadvantages:
It defeats the purpose of strnstr in that the while condition uses the unbounded string function strchr
It depends on haystack being NULL terminated, which is a deviation from the usual implementation of strnstr, for example as provided by GNU-Darwin
The call to strchr is an unnecessary function call when strchar is not inlined
Returns haystack instead of NULL when len is zero, a deviation from the accepted strstr semantics
Returns an empty string instead of haystack when needle has length of zero
The following implementation remedies the above problems without becoming as difficult to read as the GNU-Darwin implementation, and is Creative Commons licensed:
#include <string.h>
char *strnstr(const char *haystack, const char *needle, size_t len)
{
int i;
size_t needle_len;
if (0 == (needle_len = strnlen(needle, len)))
return (char *)haystack;
for (i=0; i<=(int)(len-needle_len); i++)
{
if ((haystack[0] == needle[0]) &&
(0 == strncmp(haystack, needle, needle_len)))
return (char *)haystack;
haystack++;
}
return NULL;
}
How about:
char *strnstr(char *haystack, char *needle, size_t len) {
if (len == 0) return haystack; /* degenerate edge case */
while (haystack = strchr(haystack, needle[0])) {
if (!strncmp(haystack, needle, len)) return haystack;
haystack++; }
return 0;
}
If you want haystack to not be null terminated, you'll need two length args:
char *memmem(char *haystack, size_t hlen, char *needle, size_t nlen) {
if (nlen == 0) return haystack; /* degenerate edge case */
if (hlen < nlen) return 0; /* another degenerate edge case */
char *hlimit = haystack + hlen - nlen + 1;
while (haystack = memchr(haystack, needle[0], hlimit-haystack)) {
if (!memcmp(haystack, needle, nlen)) return haystack;
haystack++; }
return 0;
}
which is available in GNU libc, though older versions are broken.
The strnstr function is not defined in the C Standard, it is available on BSD and some other systems as an extension.
Here is the man page on OS/X:
NAME
strstr, strcasestr, strnstr -- locate a substring in a string
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <string.h>
[...]
char *strnstr(const char *haystack, const char *needle, size_t len);
[...]
DESCRIPTION
[...]
The strnstr() function locates the first occurrence of the null-terminated string needle in the string haystack, where not more
than len characters are searched. Characters that appear after a '\0' character are not searched. Since the strnstr() function
is a FreeBSD specific API, it should only be used when portability is not a concern.
RETURN VALUES
If needle is an empty string, haystack is returned; if needle occurs nowhere in haystack, NULL is returned; otherwise a pointer
to the first character of the first occurrence of needle is returned.
EXAMPLES
The following sets the pointer ptr to the "Bar Baz" portion of largestring:
const char *largestring = "Foo Bar Baz";
const char *smallstring = "Bar";
char *ptr;
ptr = strstr(largestring, smallstring);
The following sets the pointer ptr to NULL, because only the first 4 characters of largestring are searched:
const char *largestring = "Foo Bar Baz";
const char *smallstring = "Bar";
char *ptr;
ptr = strnstr(largestring, smallstring, 4);
This specification is not concise enough, (the man page for the linux kernel version is even more imprecise), yet the example on BSD systems (notably above here) is clear: len is the maximum number of bytes to consider in haystack, not needle, which is just a regular null terminated C string.
Your function does not work for multiple reasons:
the semantics are incorrect as you consider length to limit s2 instead of s1
in your approach, duplicating s1 is useless and counter-productive: result, if non NULL, will point into the allocated copy that is freed before returning from the function, hence accessing the string pointed to by the return value will have undefined behavior.
strncpy does not null terminate the destination array if the source string has at least length characters before its own null terminator. You must set ss2[length] = '\0'; for your approach to work, but again, the real strnstr() function operates differently.
using malloc() and free() is probably not what you are expected to do, and failing to test for potential allocation failure is a mistake.
Here is a corrected version:
char *strnstr(const char *s1, const char *s2, size_t n) {
// simplistic algorithm with O(n2) worst case
size_t i, len;
char c = *s2;
if (c == '\0')
return (char *)s1;
for (len = strlen(s2); len <= n; n--, s1++) {
if (*s1 == c) {
for (i = 1;; i++) {
if (i == len)
return (char *)s1;
if (s1[i] != s2[i])
break;
}
}
}
return NULL;
}
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;
}
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;}
}