Function To Match The Last Character Of A String - c

So this is a problem : Write the function strend(s,t), which returns 1 if the char t occurs at the end of the string s, and zero otherwise.
This is my code:
int strend(char*, char);
int main()
{
int n = -1;
char str1[6] = "Hello", char1;
printf("Enter a character: ");
char1 = getchar();
n = strend(str1, char1);
printf("n = %d", n);
return 0;
}
int strend(char* str1, char str2)
{
while(*str1 != '\0')
{
str1++;
}
if(*str1 == str2)
{
return 1;
}
else
{
return 0;
}
}
However the character matching does not perform as intended. Where the mistake?
Thanks.

You're comparing the character to the \0 string terminator.
int strend(char* str1, char str2)
{
if (*str1 == '\0') {
return 0;
}
while(*str1 != '\0') /* removed ; that shouldn't be there */
{
str1++;
}
/* at this point, str1 is pointing to the 0-terminator */
str1--; /* pointer now points to last character of the string, not 0-terminator */
if(*str1 == str2)
{
return 1;
}
else
{
return 0;
}
}

I'll try my own explanation.
Suppose your while() loop has reached the last non-zero character of your string str1.
In this case, the line while( *str1 != '\0' ) is "asking" if this character is zero or not.
Since it is the character that you are looking for, logically it cannot be '\0'.
Then the comparison expressión is "true", and the increment str1++; is performed.
Now *str1 is the character '\0', and the immediate next iteration gives "false" when evaluating *str1 != '\0'.
Then the while() block is finished, and the program continues in the line if(*str1 == str2).
Here, the value *str1, which is '\0', is compared against str2, giving always the result "false".
However, the desired character is still in the immediate previous memory position of str1.
So, you can decrement str1 and then comparing, or well you can compare str2 against (str1 - 1).
// Option 1
str1--;
if(*str1 == str2)
//Option 2
if ((str1 - 1) == str2)

Without any error checking, (you can do that) here is a one liner that will check that the last character is matched:
int strend(char* str1, char str2)
{
return ((str1[strlen(str1)-1]) == str2)?(1):(0);
}
Or in a more readable form:
int strend(char* str1, char str2)
{
return ((str1[strlen(str1)-1]) == str2);
}

Related

How to search string with strstr but with a key word that was not assigned by the user

This is the code
int main()
{
FILE* fptr;
char c_id[50];
char str[BUFFER_SIZE];
int choices;
char* pos;
int customer_id;
printf("Enter customer ID: ");
scanf("%d", &customer_id);
sprintf(c_id, "%d", customer_id);
fptr = fopen("servicestest.txt", "r");
printf("\n1. Check for unpaid\n2. Check for paid\n");
scanf("%d", &choices);
switch (choices)
{
case 1:
while ((fgets(str, BUFFER_SIZE, fptr)) != 0)
{
pos = strstr(str, "Not");
if (pos == 1)
{
printf("%s\n", str);
}
}
break;
case 2:
while ((fgets(str, BUFFER_SIZE, fptr)) != 0)
{
pos = strstr(str, "Not");
if (pos =! 1)
{
printf("%s\n", str);
}
}
}
}
Was planning to check a line with not and print them how to do that? Why is it not printing anything when I inputted "1" as choices
I wanted to assign
char ch[50];
ch[1] = "Not";
but when i tried the strstr (str, ch[1]) it caused an error
Any idea how to do it?
check the return value of fopen:
if(!fptr) {
return -1;
}
You try to compare between a pointer and int value.
if (pos == 1)
// and
if (pos =! 1) // even you can compare, it should be if (pos != 1)
If you want to calculate the position of substring "Not", you can do as:
pos = strstr(str, "Not");
if(pos) {
int pos_substring = (int) (str-pos);
// from here you can compare the position of substring with an `int` value.
if (pos_substring == 1) {/*do something*/}
eles {/*do something*/}
}
When you try the code:
char ch[50];
char ch[1] = "Not"; // string "Not" need at least 4 bytes (3 bytes for 'N', 'o' and 't', 1 bytes for null character)
It should change to:
char ch[50] = "Not";
// or
char ch[] = "Not";
// or
const char *ch = "Not" // be attention with the string literal
Then when you want to apply to strstr function:
strstr (str, ch); // use ch instead of ch[1]
If you want to use something like strstr (str, ch[1]), you can use the 2D array of characters:
char ch[50][50] = {/*init the string here or later as you want*/}; // this 2D array contents of maximum 50 strings, each string length ups to 49.
strstr (str, ch[0]);
strstr (str, ch[1]);
strstr (str, ch[2]);
// etc.
"Why is it not printing anything when I inputted 1 as choices
char ch[1] = "Not"; is problematic, and invokes undefined behavior (UB)
The string literal "Not" has 4 characters: |N|o|t|\0|
The statement char ch[1]; creates space for only one character, accessible in the zeroth element: ch[0].
This causes the statement strstr (str, ch[1]) to also invoke UB, since ch[1] does not exist, only 1 element exists - ch[0].
The fix for this is to always provide enough space for the content needed. These are valid way to create ch with enough space:
char ch[50] = "Not";//char array of 50 initialized to "Not"
char ch[4] = "Not";//char array of 4 initialized to "Not"
char ch[] = "Not";//char array of 4 initialized to "Not" (implicitly sized)
char *ch = "Not";//char * initialized to same string literal but not editable.
Using any of these will work with as shown in your code segment:
pos = strstr(str, "Not");
But usage of the result pos is to evaluate its contents as a pointer, not as an integer:
pos = strstr(str, "Not");
//if (pos =! 1)//wrong - pos is a pointer
// if (pos =! NULL)//ok - test for non-NULL
if (pos)//ok - implicit test for non-NULL
{
printf("%s\n", str);
}

finding substring from a main string

My assignment is to find a substring from main string and return the pointer to the first character of the substring that is in mainstring and it needs to stop searching after "?" and the code has to be done without string.h . My code to me is working perfectly but the automatic checker says otherwise, checker says this
test_source.c:195:F:test_es_strstr:test_es_strstr:0: [07_altstring.d] Wrong return value with string "Foobarbaz?asd:w" and substring "baz?": Got 0x72, expected 0x7ffeb8b8a306
So the checker says that my pointer isn't in the right place.. but for me it is, need help.
My code =
const char *es_strstr(const char *str1, const char *str2) {
int i = 0;
int j = 0;
while (str1[j] != '?') ///function has to stop the search to
/// a question mark
{
if (*str1 == str2[i]) ///comparing main string first character
/// to substring first character
{
i++;
++str1;
if (*str1 == str2[i]) ///if first ones are match then look
/// for the next character matching
{
i++;
++str1;
if (*str1 == str2[i]) /// finally if 2nd is match then 3rd
{
--str1;
--str1;
printf("%c\n", *str1);
return *str1;
}
}
}
j++;
i = 0;
++str1;
}
return NULL; ///if nothing matches need to return NULL
int main(void) {
char *main = "Foobarbaz?asd:w";
char *sub = "baz?";
es_strstr(main, sub);
}
I think you should return pointer, i.e.
return str1;
instead of
return *str1;
*str means character pointed by str1

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.

How to write your own strchr in c using pointers?

Ok, so I have an assignment here from my professor. Here it is:
Write a function called strchr406. It is passed 2 parameters: a string and a char Here is the prototype for the function:
char *strchr406(char str[], char ch);
The function should return a pointer to the first instance of ch in str. For example:
char s[ ] = "abcbc";
strchr406(s, 'b'); // returns s + 1 (i.e., a pointer to the first 'b' in s)
strchr406(s, 'c'); // returns s + 2
strchr406(s, 'd'); // returns 0
He is asking us to write our own version of strchr using pointers. I looked up online for resources but none of it matches what he is asking us to do. I'm working with a group of other students, and none of us could figure this out.
How do we RETURN "s + 1"?
So far, I have this:
(I also put it online if that's easier: https://repl.it/FVK8)
#include <stdio.h>
#include "string_problems.h"
int main() {
char s[ ] = "abcbc";
strchr406(s, 'b'); // returns s + 1 (i.e., a pointer to the first 'b' in s)
strchr406(s, 'c'); // returns s + 2
strchr406(s, 'd'); // returns 0
printf("this should return %s\n", strchr406(s, 'c'));
return 0;
}
char *strchr406(char str[], char ch) {
char *p = str;
int index = 0;
while (*str != ch) {
++str;
++index;
}
if (*str == ch) {
return p + index;
} else {
return 0;
}
}
I'm getting weird outputs. Any help is appreciated.
From the manual:
char *strchr(const char *s, int c); --> the 2nd argument is an int
The strchr() and strrchr() functions return a pointer to the matched character or NULL if the character is not found.
The terminating null byte is considered part of the string,
so that if c is specified as '\0', these functions return a pointer to the terminator.
[there is no defined behaviour if the first argument happens to be NULL]
char *strchr42(char *str, int ch)
{
for (;; str++) {
if (*str == ch) return str;
if (!*str) return NULL;
}
return NULL;
}
or even shorter:
char *strchr42a(char *str, int ch)
{
do {
if (*str == ch) return str;
} while (*str++) ;
return NULL;
}
Here you are
#include <stdio.h>
char * strchr406( const char str[], char ch )
{
while ( *str && *str != ch ) ++str;
return ( char * )( ch == *str ? str : NULL );
}
int main(void)
{
char s[ ] = "abcbc";
printf( "strchr406(s, 'b') == s + 1 is %d\n", strchr406(s, 'b') == s + 1 );
printf( "strchr406(s, 'c') == s + 2 is %d\n", strchr406(s, 'c') == s + 2 );
printf( "strchr406(s, 'd') == 0 is %d\n", strchr406(s, 'd') == 0 );
printf( "this should return %s\n", strchr406(s, 'c'));
return 0;
}
The program output is
strchr406(s, 'b') == s + 1 is 1
strchr406(s, 'c') == s + 2 is 1
strchr406(s, 'd') == 0 is 1
this should return cbc
Say your professor that it will be correct to declare the function like
char * strchr406( const char str[], char ch );
^^^^^
Moreover the standard function has the following declaration
char *strchr(const char *s, int c);
because character literals in C have the type int.
So you could write the function even the following way
char * strchr406( const char str[], int ch )
{
unsigned char c = ch;
while ( *str && ( unsigned char )*str != c ) ++str;
return ( char * )( c == ( unsigned char )*str ? str : NULL );
}
As for your function then there is no sense to use the variable index because the pointer str is increased itself.
There are a couple of small things you should add or re-organize in your code to make it work.
First, this piece of code
while (*str != ch) {
++str;
++index;
}
will not stop at the end of your string and will continue looping until it finds your char somewhere after the string in the virtual memory of the process.
So you should probably have a condition for stopping that checks for the end of the string (strings in C ends with the char \0, ASCII code = 0):
while (*str != '\0')
Second thing, you are comparing ch with the current char of the string after the loop. You should probably move this code inside the loop: you need to check every character of the string against ch. Also, you don't need to use both an index and increment the pointer str. So you can get rid of the index variable. If at anytime in your loop you find the correct ch then you can directly return the pointer to it using str. If you get out of your loop, it means that you did not find the ch inside str and then you can return NULL (cf man strchr for more on return values).
char *strchr406(char str[], char ch)
{
while (*str != '\0')
{
if (*str == ch)
{
return (str);
}
str++;
}
return (NULL);
}
Note that in this context, even though NULL is 0, it's better to use NULL since you are supposed to return a pointer.
Last thing, if you want to do exactly like strchr, then if ch is '\0' you should return the pointer to the '\0' at the end of the string str. From the man: The terminating null byte is considered part of the string, so that if c is specified as '\0', these functions return a pointer to the terminator. So your code becomes:
char *strchr406(char str[], char ch)
{
while (*str != '\0')
{
if (*str == ch)
{
return (str);
}
str++;
}
/**
* if ch is '\0', you should return
* the pointer to the `\0` of the string str
*/
if (*str == ch)
{
return (str);
}
return (NULL);
}
Note: Thanks to #chux for pointing this last thing out.
Note 2: You don't need to check if str is NULL in this context.
Note 3: The "official" prototype for strchr is char *strchr(const char *s, int c); so depending on your project requirements you might want to update your prototype to match to this one.

Why a string is not nulled terminated when passing in a function?

This is my call:
testFunc(0,0,"+++++A+++b+c++++d+e++++f+g+++++h+i","Abcdefghi");
To the function:
void testFunc(int isRight, int step, const char* str1, const char* str2)
{
static int testNum = 1;
printf("test%d: %d\n", testNum++, extendedSubStr(isRight, step, str1, str2));
}
That calls:
int extendedSubStr(int isRight, int gap, const char* str1, const char* str2)
{
// find location of the first char
char * pch;
char * firstOcur;
pch=strchr(str1,str2[0]);
firstOcur = pch;
int i=0;
while (pch!=NULL)
{
i++;
// find next char from the remaining string
pch=strchr(pch+1,str2[i]);
}
if(i==strlen(str2))
{
// return position of the first char
return firstOcur-str1;
}
}
My problem starts when i try to iterate through str1 using strchr() which expects a null terminated string. It keeps looping for some reason. I would prefer not to use memchr().
Why str1 and str2 aren't nulled terminated? How can i terminate them?
The two strings are definitely null terminated. What happens is that your code iterates past the null terminators.
You need to stop iterating when str2[i] reaches \0:
int i = 1;
while (pch != NULL && str2[i] != 0)
{
pch = strchr(pch + 1, str2[i++]);
}
From the strchr manpage:
The terminating null character is considered to be part of the string; therefore if c is \0,
the functions locate the terminating \0.
Basically, what happens is that once you reach the null character in str2, you match the null character in str1. After this, your loop proceed to look for characters that appear past the end of str2 in memory that follows str1. Chaos ensues.
use
while (pch!=NULL && *(pch+1)!='\0' && str2[i]!='\0')
instead of
while (pch!=NULL)
As others already mentioned, C style strings are terminated with '\0'.
You might want to look at strstr(s1, s2). strstr looks for the position of s2 in s1. Since the parameters isRight and gap aren't used, this would simplify extendedSubStr
int extendedSubStr(int isRight, int gap, const char* str1, const char* str2)
{
char *r = strstr(str1, str2);
return r != NULL ? r - str1 : -1;
}

Resources