How to make strcmp function? - c

I want to make my own strcmp function, like the one in C.
int my_cmp(const char* str1, const char* str2)
{
int index;
for (index = 0; str1[index] != '\0' && str2[index] != '\0'; index++)
if (str1[index] != str2[index])
return (str1[index] - str2[index]);
return 0;
}
Am I right?
I know that not all the strings have the same length.
I'm not sure about condition of for statement.

Here is one of the Official implemention.
int strcmp(const char *s1, const char *s2)
{
for ( ; *s1 == *s2; s1++, s2++)
if (*s1 == '\0')
return 0;
return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1);
}
Update:
Problems of your code:
your code works fine for string of the same length, the other cases it will false.
For Extended ASCII(range between 128~255), you use sign char, so their value would overflow to an negative value, then you may get a wrong value.
fix version:
int my_cmp(const char* str1, const char* str2)
{
int index;
for (index = 0; str1[index] != '\0' && str2[index] != '\0'; index++)
if (str1[index] != str2[index])
return ((*(unsigned char *)str1 < *(unsigned char *)str2) ? -1 : +1);
// here is the fix code.
if (str1[index] != '\0') {
return 1;
} else if (str2[index] != '\0') {
return -1;
}
return 0;
}

the following code snippet shows you how you could implement an "strcmp" function:
int myStrCmp (const char *s1, const char *s2) {
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;
while (*p1 != '\0') {
if (*p2 == '\0') return 1;
if (*p2 > *p1) return -1;
if (*p1 > *p2) return 1;
p1++;
p2++;
}
if (*p2 != '\0') return -1;
return 0;
}

Am I right? I know that not all the strings have the same length. I'm not sure about condition of for statement.
You are almost right. Your if statement
if (str1[index] != str2[index])
return (str1[index] - str2[index]);
is basically correct (though the characters should be subtracted as unsigned chars), but the for loop itself
for (index = 0; str1[index] != '\0' && str2[index] != '\0'; index++)
is wrong. Specifically the condition:
str1[index] != '\0' && str2[index] != '\0'
This is wrong because it checks to make sure that both characters at the given index are not '\0', rather than either character. This can be fixed by replacing && with ||.
Here's how a seasoned C programmer might write the strcmp function (I wrote this :p (EDIT: #chux suggested an improvement)):
int strcmp(const char *s1, const char *s2) {
for (; *s1 && (*s1 == *s2); s1++, s2++) {}
return (unsigned char)(*s1) - (unsigned char)(*s2);
}

Related

Recreate the strstr() function

Hello i am trying to make my own strstr() function and i can't figure out why it is returning a segmentation fault.I am trying to search a string within another string and then return a pointer to the first 'same' letter. Any help would be appreciated.
This is my code:
char* ms_search(char *Str1,char* Str2){
char* p = NULL;
int i,k=0,j = 0;
for(i = 0;i < ms_length(Str1); i++){
if(Str1[i] == Str2[k]){
if(k == 0){
p = &Str1[i];
j= i;
}
if(k == ms_length(Str2)){
break;
}
k++;
}
else{
if(Str1[i] == Str2[0]){
p = &Str1[i];
k=1;
j= i;
}
else{
j=0;
k = 0;
p = NULL;
}
}
}
if(p != NULL){
Str1[ms_length(Str2)+1] = '\0';
}
return &Str1[j];
}
int main(){
int i;
char* p2;
char* p="lolaaa";
char* p1= "aaa";
//char ar2[] = "aaa4";
//ms_copy(p,p1);
//printf("%s",p);
//ms_nconcat(p,p1,3);
//if(ms_ncompare(p,p1,3) == 1) printf("einai idia");
p2 = ms_search(p,p1);
printf("%s",p2);
return 0;
}
Hello i am trying to make my own strstr()
First of all you have to follow the C standard.
The C89/C99 prototype is:
char *strstr(const char *s1, const char *s2);
Standard strstr() function will NOT change the passed buffers.
The functionality is described as:
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.
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.
In standard C, this can be implemented as:
#include <string.h> /* size_t memcmp() strlen() */
char *strstr(const char *s1, const char *s2)
{
size_t n = strlen(s2);
while(*s1)
if(!memcmp(s1++,s2,n))
return (char *) (s1-1);
return 0;
}
The standalone implementation is given below:
#include <stdio.h>
char *strstr1(const char *str, const char *substring)
{
const char *a;
const char *b;
b = substring;
if (*b == 0) {
return (char *) str;
}
for ( ; *str != 0; str += 1) {
if (*str != *b) {
continue;
}
a = str;
while (1) {
if (*b == 0) {
return (char *) str;
}
if (*a++ != *b++) {
break;
}
}
b = substring;
}
return NULL;
}
int main (void)
{
char string[64] ="This is a test string for testing strstr";
char *p;
p = strstr1 (string,"test");
if(p)
{
printf("String found:\n" );
printf ("First occurrence of string \"test\" in \"%s\" is:\n%s", string, p);
}
else
{
printf("String not found!\n" );
}
return 0;
}
Output:
String found:
First occurrence of string "test" in "This is a test string for testing strstr" is:
test string for testing strstr
Your standalone strstrl is correct.
I have my preferences, and you have yours.
Neither is perfect.
You prefer
if ( *b == 0 ) {
return (char *) s1;
}
I prefer
if ( ! *b ) return (char *) s1;
You prefer
str += 1;
I prefer
str++;
You prefer
while (1)
I prefer
for (;;)
If I rewrite your strstrl with my preferences, we get
char *strstr1(const char *str, const char *substring)
{
const char *a, *b = substring;
if ( !*b ) return (char *) str;
for ( ; *str ; str++) {
if (*str != *b) continue;
a = str;
for (;;) {
if ( !*b ) return (char *) str;
if (*a++ != *b++) break;
}
b = substring;
}
return NULL;
}
Note that this version has the same snippet
if ( ! *b ) return (char *) str;
in two locations. Can we rearrange to do that test only once?
Note how we do two tests when lead character matches
if ( *str != *b )
and again later for the same lead char
a = str ; if ( *a++ != *b++)
Can we rearrange that to do a single test?
My rewrite of your standalone strstr is below. It might not be
your style, but it is in many ways similar to your standalone strstr.
My rewrite is shorter and, I want to believe, easier to understand.
char *strstr(const char *str, const char *substring)
{
const char *a = str, *b = substring;
for (;;) {
if ( !*b ) return (char *) str;
if ( !*a ) return NULL;
if ( *a++ != *b++) { a = ++str; b = substring; }
}
}

C - Determining alphabetical order of characters/strings

I'm trying to write a function that compares two strings (s1 and s2) and works out whether s1 comes before, after or is equal to the s2 string, alphabetically (in the same way as a dictionary is read). If s1 comes before s2 it should return -1. If it's equal to s2 it should return 0. If it comes after s2 it should return 1.
I'm having difficulty getting the function to work - I can only seem to get returns for the first chars in each string and only using the same case. Grateful for any help you can give.
Here's the code so far:
#include <stdio.h>
#include <stdlib.h>
int cmpstr(const char *, const char *);
int main()
{
printf("Test 1: %d\n", cmpstr( "Hello", "World"));
printf("Test 2: %d\n", cmpstr( "Hello", "Hello"));
printf("Test 3: %d\n", cmpstr( "World", "Hello"));
return 0;
}
int cmpstr(const char *s1, const char *s2)
{
/*compare corresponding string characters until null is reached*/
while(*s1 != '\0' && *s2 != '\0' )
{
if (*s1 < *s2)
{
return -1;
}
else if (*s1 > *s2)
{
return 1;
}
else
{
return 0;
s1++;
s2++;
}
}
return 0;
}
just remove the last else part and put return 0 out of loop because both string are only equal if if part and else-if part will not be true, when it will come out from loop it will return 0.
int cmpstr(const char *s1, const char *s2)
{
/*compare corresponding string characters until null is reached*/
while(*s1 != '\0' && *s2 != '\0' )
{
if (*s1 < *s2)
{
return -1;
}
else if (*s1 > *s2)
{
return 1;
}
s1++;
s2++;
}
return 0;
}
Your code has a very obvious mistake, which is the return 0-statement making the s1++;s2++ to unreachable code (your compiler should have warned you about that).
But it has also a conceptual mistake, as it ignores situations where s1 is longer than s2 or vice versa. So in your approach (once corrected the return 0-thing, "Hello" and "Hello there" would compare equal.
See the following code with works in a different manner. It skips equal characters until one (or both) strings has (have) ended. Then, according to this state, result is determined:
int cmpstr(const char *s1, const char *s2)
{
while (*s1 && *s2 && *s1 == *s2) { // move forward until either one of the strings ends or the first difference is detected.
s1++;
s2++;
}
int result = (*s1 - *s2);
// if both strings are equal, s1 and s2 have reached their ends and result is 0
// if *s1 > *s2, s1 is lexographically greater than s2 and result is positive
// if *s1 < *s2, s1 is lexographically lower than s2 and result is negative
// normalize "positive" and "negative" to 1 and -1, respectively
if (result < 0)
result = -1;
else if (result > 0)
result = 1;
return result;
}
Removing 'return 0' in else statement will work. If the chars are equal in same level, you need to look next ones until the equality breaks.
Edit: Also, you need to think about when lengths of strings are not equal.
int cmpstrMY(const char *s1, const char *s2)
{
char sc1, sc2;
/*compare corresponding string characters until null is reached*/
while (1)
{
sc1 = towlower(*s1);
sc2 = towlower(*s2);
if (sc1 == '\0' && sc2 == '\0') {
break;
}
else if (sc1 == '\0' && sc2 != '\0') {
return -1;
}
else if (sc1 != '\0' && sc2 == '\0') {
return 1;
}
else if (sc1 < sc2)
{
return -1;
}
else if (sc1 > sc2)
{
return 1;
}
else
{
s1++;
s2++;
}
}
return 0;
}
Your cmpstr must be something like the code above.

C function to compare last elements of a string to another using pointers

My problem is to see if str1 ends with the contents of str2.
I tried this:
int string_ends_with(const char *str1, const char *str2) {
int len;
len = strlen(str2);
while ((*str1 == '\0' - len) && *str1 != '\0') {
if (strcmp(str1, str2) == 0) {
return 1;
} else {
return 0;
}
}
}
int main() {
char str[10] = "banana";
char str1[5] = "ana";
string_ends_with(str, str1);
return 0;
}
What I am doing wrong?
This problem needs to be solved only using pointers.
This condition in the while statement
while((*str1 == '\0' - len) && *str1 != '\0')
does not make sense. What does '\0' - len mean ?
You could write the function the following way
int string_ends_with(const char *str1, const char *str2)
{
size_t n1 = strlen( str1 );
size_t n2 = strlen( str2 );
return n2 <= n1 && strcmp( str1 + n1 - n2, str2 ) == 0;
}
If you may not use standard functions then you can write the function the following way
int string_ends_with(const char *str1, const char *str2)
{
const char *p1 = str1;
const char *p2 = str2;
while ( *p1 ) ++p1;
while ( *p2 ) ++p2;
while ( p1 != str1 && p2 != str2 && *p1 == *p2 ) --p1, --p2;
return p2 == str2 && *p1 == *p2;
}
This will be useful if you want to know which string has a greater/lesser value.
int string_ends_with(char *p1, char *p2)
{
char *q1;
char *q2;
if (! p1 || ! p2)
return something;
(p1 + (strlen(p1) - 1));
(p2 + (strlen(p2) - 1));
while (q1 >= p1 && q2 >= p2) {
if (*q2 < *q1) return -1;
else if (*q2 > *q1) return 1;
q1--; q2--;
}
return 0;
}
EDIT: Of course do basic error checking, i'd presume that's a given for most and prefer not to clutter my meagre offering with un-necessary code with regards to a simple example. Still, don't want to ruffle any feathers.
Alright.
You initial test is incorrect, as noted in the other answers.
Here is a slightly smaller and potentially more efficient version:
int string_ends_with(const char *str1, const char *str2) {
const char *p1 = str1;
const char *p2 = str2;
while (*p1) p1++; // same as p1 += strlen(p1);
while (*p2) p2++; // same as p2 += strlen(p2);
while (p2 != str2) {
if (p1 == str1 || *--p1 != *--p2)
return 0;
}
return 1;
}
Note that your main test function should output something and perform more tests:
void test(const char *a, const char *b) {
printf("\"%s\" ends with \"%s\": %s\n",
a, b, string_ends_with(a, b) ? "yes" : "no");
}
int main(void) {
char str[] = "banana";
char str1[] = "ana";
test(str, str1);
test(str1, str);
test(str, str);
test(str, "");
test("", str);
test("", "");
return 0;
}

Merging two strings together in C, switching off characters

I am trying to merge two strings of variable length in C. The result should be 1st character from str1 then 1st character from str2 then 2nd character from str1, 2nd character from str2, etc. When it reaches the end of one string it should append the rest of the other string.
For Example:
str1 = "abcdefg";
str2 = "1234";
outputString = "a1b2c3d4efg";
I'm pretty new to C, my first idea was to convert both strings to arrays then try to iterate through the arrays but I thought there might be an easier method. Sample code would be appreciated.
UPDATE:
I've tried to implement the answer below. My function looks like the following.
void strMerge(const char *s1, const char *s2, char *output, unsigned int ccDest)
{
printf("string1 is %s\n", s1);
printf("string2 is %s\n", s2);
while (*s1 != '\0' && *s2 != '\0')
{
*output++ = *s1++;
*output++ = *s2++;
}
while (*s1 != '\0')
*output++ = *s1++;
while (*s2 != '\0')
*output++ = *s2++;
*output = '\0';
printf("merged string is %s\n", *output);
}
But I get a warning when compiling:
$ gcc -g -std=c99 strmerge.c -o strmerge
strmerge2.c: In function ‘strMerge’:
strmerge2.c:41:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
And when I run it it doesnt work:
./strmerge abcdefg 12314135
string1 is abcdefg
string2 is 12314135
merged string is (null)
Why does it think argument 2 is an int and how do I fix it to be a char? If I remove the "*" off output in the printf it doesn't give a compile error but the function still doesn’t work.
The code below ensures that the strings can't overflow by making the output string as long as the two input strings, and using fgets() to ensure that there is no overflow of the input strings. One alternative design would do dynamic memory allocation (malloc() et al), at the cost of the calling code having to free() the allocated space. Another design would pass the length of the output buffer to the function so that it could ensure no overflow occurs.
The test program doesn't emit prompts: it would not be hard to add a function to do so.
Code
#include <stdio.h>
#include <string.h>
void interleave_strings(const char *s1, const char *s2, char *output)
{
while (*s1 != '\0' && *s2 != '\0')
{
*output++ = *s1++;
*output++ = *s2++;
}
while (*s1 != '\0')
*output++ = *s1++;
while (*s2 != '\0')
*output++ = *s2++;
*output = '\0';
}
int main(void)
{
char line1[100];
char line2[100];
char output[200];
if (fgets(line1, sizeof(line1), stdin) != 0 &&
fgets(line2, sizeof(line2), stdin) != 0)
{
char *end1 = line1 + strlen(line1) - 1;
char *end2 = line2 + strlen(line2) - 1;
if (*end1 == '\n')
*end1 = '\0';
if (*end2 == '\n')
*end2 = '\0';
interleave_strings(line1, line2, output);
printf("In1: <<%s>>\n", line1);
printf("In2: <<%s>>\n", line2);
printf("Out: <<%s>>\n", output);
}
}
Example output
$ ./interleave
abcdefgh
1234
In1: <<abcdefgh>>
In2: <<1234>>
Out: <<a1b2c3d4efgh>>
$
char* getMerged(const char* str1, const char* str2) {
char* str = malloc(strlen(str1)+strlen(str2)+1);
int k=0,i;
for(i=0;str1[i] !='\0' && str2[i] !='\0';i++) {
str[k++] = str1[i];
str[k++] = str2[i];
}
str[k]='\0';
if (str1[i] != '\0') {
strcpy(&str[k], &str1[i]);
} else if (str2[i] != '\0') {
strcpy(&str[k], &str2[i]);
}
return str;
}
Your strMerge prints null because, you print the valueAt(*)output which was assigned null the previous step.
#include<stdio.h>
#include<string.h>
//strMerge merges two string as per user requirement
void strMerge(const char *s1, const char *s2, char *output)
{
printf("string1 is %s\n", s1);
printf("string2 is %s\n", s2);
while (*s1 != '\0' && *s2 != '\0')
{
*output++= *s1++;
*output++ = *s2++;
}
while (*s1 != '\0')
*output++=*s1++;
while (*s2 != '\0')
*output++ = *s2++;
*output='\0';
}
int main()
{
char *str1="abcdefg";
char *str2="1234";
char *output=malloc(strlen(str1)+strlen(str2)+1); //allocate memory 7+4+1 = 12 in this case
strMerge(str1,str2,output);
printf("%s",output);
return 0;
}
OUTPUT:
string1 is abcdefg
string2 is 1234
a1b2c3d4efg
In C, both strings are already arrays that can be accessed by their pointers. You just need to create a new buffer that's large enough, then copy into it.
E.g. something like this:
int str1Length = strlen(str1);
int str2Length = strlen(str2);
char* output = (char*) malloc(str1Length + str2Length + 1);
int j = 0;
for (int i = 0; i < str1Length; i++)
{
output[j++] = str1[i];
if (str2Length < i)
output[j++] = str2[i];
}
if (str2Length > str1Length)
{
for (int i = str2Length - str1Length; i < str2Length; i++)
{
output[j++] = str2[i];
}
}

Removing all occurences of all charactesr from second string in first string

I have a small problem.
I have a function that takes in two parameters (two strings). For example:
String1 = "hello"
String2 = "leo"
I need to remove all characters from String2 in String1. In this case, my final result should be: "h". I need to incorporate pointers when doing this! I've got this code so far, but it's only remove "e" from "hello". I don't know why it's not working. If someone has a better or efficient way of doing this, please help!
void rmstr(char str1[], char str2[])
{
//Pointers to traverse two strings
char *p_str1 = &str1[0];
char *p_skip;
int length = (int)strlen(str2);
int i;
while(*p_str1 != '\0')
{
for (i = 0; i < length; i++)
{
if(*p_str1 == str2[i])
{
for(p_skip = p_str1; *p_skip == str2[i]; ++p_skip);
memcpy(p_str1, p_skip, &str1[strlen(str1)+1] - p_skip);
}
if(*p_str1 != '\0')
{
++p_str1;
}
}
}
}
char* rmstr(char *str1, char *str2, char *ans) {
char *p1 = str1;
char *p2 = str2;
char *res = ans;
while (*p1 != '\0') {
p2 = str2;
while (*p2 != '\0') {
if (*p1 == *p2) // A character in str1 is found inside str2
break;
p2++;
}
if (*p2 == '\0') { // No match found
*ans = *p1;
ans++;
}
p1++;
}
*ans = '\0';
return res;
}
Testing code:
int main(void) {
char str1[] = "hello";
char str2[] = "elo";
char ans[10];
printf(rmstr(str1, str2, ans));
return 0;
}
Well, this answer has less variables and maybe easier to read.
#include "stdio.h"
/* check if c belongs to the second str */
int char_belong_to_str(char c, char *str)
{
while(*str)
if (c == *str++)
return 1;
return 0;
}
void rmstr(char str1[], char str2[])
{
int result_len = 0; /* saves the result str len*/
char * p_new = str1;
while (*str1)
{
char c = *str1;
if (!char_belong_to_str(c, str2)) /* if not found in str2, save it*/
{
*(p_new + result_len) = c;
++result_len;
}
++str1;
}
*(p_new+result_len) = '\0';
printf("%s \n", p_new);
}
int main()
{
char p1[] = "hello";
char p2[] = "elo";
rmstr(p1, p2);
return 0;
}

Resources