I'm trying to compare two strings, and even though they look the same, I wasn't getting a match. Turns out one string contains \n.
So my question is, is a way to check if a string contains '\n'?
I'm using the strcmp function;
char *tempData;
char *checkThis;
tempData = "Hello \n";
checkThis = "Hello";
if(strcmp(tempData, checkThis) == 0)
{
printf("Match");
}
You could strip the white-space before comparing, then you do not require a check for '\n'. But instead you can just compare the strings, assuming that is what you want to do.
This question has some answers on how to do that in C.
Create your own comparing function, that ignores the \n or any other char you pass in:
int strcmp_ignoring_char(const char* s1, const char* s2, const char ignore)
{
while ( *s1 != '\0' && *s1 != '\0' )
{
if ( *s1 == ignore )
{
s1++;
continue;
}
if ( *s2 == ignore )
{
s2++;
continue;
}
if ( *s1 != *s2 )
return *s1 > *s2 ? 1 : -1;
s1++;
s2++;
}
/* modified to account for trailing ignore chars, as per Lundin comment */
if ( *s1 == '\0' && *s2 == '\0' )
return 0;
const char* nonEmpty = *s1 == '\0' ? s2 : s1;
while ( *nonEmpty != '\0' )
if ( *nonEmpty++ != ignore )
return 1;
return 0;
}
This way you won't scan the strings twice.
You could also create a variation that ignores a string, not a single char:
int strcmp_ignoring_char(const char* s1, const char* s2, const char* ignore)
Here is my attempt. I have tried to keep it MISRA-C compliant, save for the C99 features.
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
#include <stdio.h>
int8_t strcmp_ignore_space (const uint8_t* s1, const uint8_t* s2)
{
while ((*s1 != '\0') && (*s2 != '\0'))
{
bool space1 = isspace(*s1);
bool space2 = isspace(*s2);
if(space1)
{
s1++;
}
if(space2)
{
s2++;
}
if (!space1 && !space2)
{
if (*s1 != *s2)
{
break;
}
else
{
s1++;
s2++;
}
}
} // while ((*s1 != '\0') && (*s2 != '\0'))
if(*s1 != '\0') // remove trailing white spaces
{
while(isspace(*s1))
{
s1++;
}
}
if(*s2 != '\0') // remove trailing white spaces
{
while(isspace(*s2))
{
s2++;
}
}
return (int8_t)( (int16_t)*s1 - (int16_t)*s2 );
}
int main()
{
// obscure strings with various white space characters, but otherwise equal
if(strcmp_ignore_space(" He\vllo \n",
"\r He\fll o ") == 0)
{
printf("Same\n");
}
else
{
printf("Different\n");
}
return 0;
}
Related
char *myfgets(char *s, int n, FILE *in) {
char ch;
if (n<=0) {
return s;
}
while (((ch = getc(in)) != '\n')) {
if(ch == EOF){
return NULL;
}
else if (ch == '\n') {
break;
} else {
*s=ch;
s++;
}
}
*s = '\n';
if (ferror(in) != 0) {
return NULL;
} else {
return s;
}
if (strlen(s) > 512) {
return NULL;
}
}
I want to take 1 line only from some specific file and put the line into the char pointer (*s). I made this function but when I run the program it didn't work really well. For the result, there are a lot of unknown characters that are displayed.
Is there anything wrong with my code?
From the man page of strlen():
The strlen() function calculates the length of the string pointed to by s, excluding the terminating null byte ('\0').
So, strlen counts the number of characters until it finds a null byte '\0', and not the newline character '\n'. Consider changing
*s = '\n'
to
*s = '\0'
Alternatively, you could write your own strlen that looks for '\n' instead of '\0'.
I should check if 2 arrays are equal using exact function _Bool areEqual(char *str1,char *str2). My code terminates. What should I do in order to effectively use _Bool function to print true (if they are equal) and false( not equal).
My code:
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
_Bool areEqual(char* str1, char* str2) {
while (str1 != '\0') {
if (str1 == str2) {
str1++;
if (str1 = '\0') {
return true;
}
}
else {
return false;
}
}
}
int main() {
char arr[] = "abcdef";
char* ptr = "abcdef";
areEqual(arr, ptr);
return 0;
}
Firstly, to simplify bool is an alias to _Bool so they are similar.
Secondly, your function AreEqual is actually comparing the content of s1 with the first charachter of s2, if you want to compare all the content of the strings you need to iterate on both
_Bool areEqual(char *s1, char *s2)
{
int i = 0;
while (s1[i] != '\0' && s2[i] != '\0') {
if (s1[i] != s2[i])
return false;
i++;
}
if (s1[i] != '\0' || s2[i] != '\0') //string with different length
return false;
return true
}
Finaly to print the corresponding result you just need to check the return of your function
if (areEqual(str1, str2) == true)
printf("True");
else
printf("False");
I am trying to remove unnecessary whitespace from my char* for future use. Basically, I want to only have one space between words and remove any additional spaces, tabs, or new line characters in between words. The current code I have almost works I believe, but I am unable to read the memory of the individual characters I am storing in my array. Also any solution must not have a maximum character size so if dynamic memory allocation is needed that would need to be considered as well. Is there a way to get this working? Thanks
EDIT 1: trailing and leading spaces should also be removed. Thanks to #Vlad from Moscow for the clarification
int main()
{
char* fileString1;
fileString1=removeAdditionalWhiteSpace(fileString1);
}
char* removeAdditionalWhiteSpace(char* wordList)
{
char characterHolder;
char* finalList[strlen(wordList)];
char* delimeter = wordList;
int i = 0;
do
{
finalList[i] += characterHolder;
char* hasSpace = NULL;
while (*delimeter == ' ' || *delimeter == '\n' || *delimeter == '\t')
{
if(*delimeter == ' ')
{
if(hasSpace==NULL)
{
hasSpace = delimeter;
characterHolder = *delimeter;
}
else
{
++delimeter;
}
}
else if(*delimeter == '\n' || *delimeter == '\t')
{
*delimeter = ' ';
if(hasSpace==NULL)
{
hasSpace = delimeter;
characterHolder = *delimeter;
}
else
{
++delimeter;
}
}
}
hasSpace=NULL;
characterHolder = *delimeter;
i++;
}
while( (*wordList++ = *delimeter++) );
return *finalList;
}
Your function does not make sense and has undefined behavior.
For example the variable characterHolder was not initialized and it is added to pointer finalList[i]
char characterHolder; // <===
char* finalList[strlen(wordList)];
char* delimeter = wordList;
int i = 0;
do
{
finalList[i] += characterHolder; // <===
//….
If you need to remove redundant white spaces from a string including its leading and trailing white spaces then the function can look as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
char * remove_duplicate_spaces( char *s )
{
char *src = s, *dsn = s;
while ( isspace( ( unsigned char )*src ) ) ++src;
do
{
char c = *src;
if ( isspace( ( unsigned char )c ) ) c = ' ';
if ( c == ' ' )
{
while ( isspace( ( unsigned char ) *++src ) );
if ( *src )
{
*dsn++ = c;
}
}
*dsn++ = *src;
} while ( *src++ );
return s;
}
int main(void)
{
char s[] = "\t\tIt is\t\ta very\nlong\nstring.\t\t";
printf( "\"%s\"\n", s );
printf( "\"%s\"\n", remove_duplicate_spaces( s ) );
return 0;
}
Its output is
" It is a very
long
string. "
"It is a very long string."
Man that looks super complicated.
Here's a simple function to remove whitespace from the string:" This is a test \t of some \n Extra white space. "
#include <stdio.h>
#include <ctype.h>
void removeWS(char* text)
{
char* d = text;
while (isspace(*text)) ++text;
while(*text)
{
*d = isspace(*text)? ' ' : *text;
text++;
while (isspace(*d) && isspace(*text)) ++text;
if (*text) d++;
}
*d = *text;
}
int main(void) {
char text[] = " This is a test \t of some \n Extra white space. ";
removeWS(text);
printf("%s\n", text);
return 0;
}
Sample Output:
Success #stdin #stdout 0s 4284KB
This is a test of some Extra white space.
Minimalistic approach:
size_t delspaces(char * str)
{
size_t src, dst;
size_t cnt;
for (cnt=src=dst=0; str[dst] = str[src++]; ) {
if (isspace(str[dst])) {
if (dst && !cnt++) str[dst++] = ' '
continue;
}
cnt=0;
dst++;
}
// remove trailing spaces
while (dst && isspace(str[dst-1])) str[--dst] = 0;
// return the string length of the resulting string
// (which could be useful for the caller)
return dst;
}
Final note: the last while() could be an if(), since there can be only one trailig space.
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.
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);
}