strcmp misbehave with 2 same strings - c

I have this code:
#include <stdio.h>
#include <string.h>
int main() {
char s1[50], s2[50];
printf("write s1:\n");
fgets(s1, sizeof(s1), stdin);
printf("s2:\n");
fgets(s2, sizeof(s2), stdin);
printf("The concatenation of the two strings: %s\n", strcat(s1, s2));
if( strcmp(s2, s1) < 0 ) {
printf("s2 is shorter than s1.\n");
} else if( strcmp(s2, s1) > 0 ) {
printf("s2 is longer than s1.\n");
} else {
printf("strings are equal.\n");
}
return 0;
}
The problem is that when I write 2 same strings like abc or whatever, strcmp return "s2 is shorter than s1."
Is that the normal output or have I done anything wrong? If so, where?
Or strcat makes the string not equal? Can anything be done about this?
Thank you

You are doing
strcat(s1, s2)
before comparing. Which will modify string s1 so strings will not be equal

you are doing a strcat before doing doing strcmp. strcat would concatenate s2 to s1

Strcmp compares the strings according to the value of their contents (similar to the dictionary order, if you like, but not exactly that) not according to their length.
For example: "abc" > "abb"

Try replacing
printf("The concatenation of the two strings: %s\n", strcat(s1, s2));
with
printf("The two strings are: '%s' and '%s' and their concatenation: '%s'\n",
s1, s2, strcat(s1, s2));
Then read a description of strcat.
If that doesn't help, replace %s sequences with %p. (Possibly you'll have to read a description of the %p format specifier in the printf documentation.)

Related

Passing char pointers between functions - Are both ways equal? - C

I have done one MCVE code of passing char pointers into other function. I have the dude if both ways of passing char pointer parameter are equal (how str1 and str2 are passed into passingCharPointer1 and passingCharPointer2 respectably).
Also, I have include comments inside code with the behavior of the free/null functions and their behavior (I would appreciate it if they were also read).
The code is:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 50
void passingCharPointer1(char *str) {
strcpy(str, "Hi-1!");
}
void passingCharPointer2(char **str) {
strcpy(*str, "Hi-2!");
}
int main() {
// Init char pointers
char *str1 = malloc((MAX_LENGTH +1)*sizeof(char));
char *str2 = malloc((MAX_LENGTH +1)*sizeof(char));
// Gets their values
printf("Input string 1: ");
fgets(str1, MAX_LENGTH , stdin);
printf("Input string 2: ");
fgets(str2, MAX_LENGTH , stdin);
printf("\n");
// Remove '\n' character
str1[strcspn(str1, "\n")] = '\0';
str2[strcspn(str2, "\n")] = '\0';
// Print their values
printf("BEFORE - Function 1: %s\n", str1);
printf("BEFORE - Function 2: %s\n", str2);
// Pass to function in two ways - ARE BOTH WAYS EQUAL?
passingCharPointer1(str1);
passingCharPointer2(&str2);
// Print their values
printf("AFTER - Function 1: %s\n", str1);
printf("AFTER - Function 2: %s\n", str2);
// Freeing pointers
free(str1);
free(str2);
// Print their values after freeing
printf("\nAFTER FREE 1: %s\n", str1); // Show rare characters (I supposse it is normal behaviour after free)
printf("AFTER FREE 2: %s\n", str2); // Continue having its content (I supposse it is not normal behaviour after free)
// Nulling pointers
str1 = NULL;
str2 = NULL;
// Print their values after nulling
printf("\nAFTER NULL 1: %s\n", str1); // Normal behaviour
printf("AFTER NULL 2: %s\n", str2); // Normal behaviour
// Exit success
return 0;
}
In general the functions are not equivalent. The first function accepts pointer by value while the second function accepts pointer by reference. As result the second function can change the original pointer used in an expression as the argument.
Consider the following demonstrative program
#include <stdio.h>
void passingCharPointer1( char *s )
{
s = "Bye";
}
void passingCharPointer2( char **s )
{
*s = "Bye";
}
int main(void)
{
char *s1 = "Hello";
char *s2 = "Hello";
printf( "Before function calls: %s %s\n", s1, s2 );
passingCharPointer1( s1 );
passingCharPointer2( &s2 );
printf( "After function calls: %s %s\n", s1, s2 );
return 0;
}
Its output is
Before function calls: Hello Hello
After function calls: Hello Bye
Pay atttention to that accessing memory after it was freed invokes undefined behavior.
If you question is truly:
is equal both ways of passing parameters (function1 and function2)
(and you ignore all of the code in main()), then yes, the two functions are essentially equivalent.
The difference is that function1 takes a pointer to a char (which, in the C language, is an idiom for a string) and function2 takes a pointer to a pointer to a char.
But as #Vlad from Moscow points out, function2 allows you to modify the pointer passed into the function.

Can I set non-alphabetic characters as a delimeter in c when using fscanf?

I'm trying to read strings from a file using
while(fscanf(fd, "%s ", word) != EOF) {}
Where fd is the file and word is where I'm storing the string.
However, this effectively uses the whitespace as the delimeter. Currently, if I have a file that reads "this% is, the4 str%ng" it would result in strings "this%", "is,", "the4", and "str%ng". I need it to be "this" "is" "the" "str" "ng". Is it possible to do this with fscanf, or is there something else I need to use?
I saw some answers here and here but they didn't seem to help me out.
Those answers show the use of the "%[] format specifier. As an example suppose you have this to get two strings from the console:
#include <stdio.h>
int main(void){
char s1[100] = "", s2[100] = "";
int res;
res = scanf("%99[^%]%%%99[^%]%%", s1, s2);
printf("%d %s %s\n", res, s1, s2);
}
The first % starts the each format spec, the ^% tells scanf to stop at %, and the next "escaped" double % tells scanf to read the % that stopped the scan. It then repeats for the second string, so the format spec for one string is %99[^%]%% .
To make the format look simpler, suppose the delimiter is not % but #, then the code would be:
#include <stdio.h>
int main(void){
char s1[100] = "", s2[100] = "";
int res;
res = scanf("%99[^#]#%99[^#]#", s1, s2);
printf("%d %s %s\n", res, s1, s2);
}
The function fscanf is similar.
EDIT
This answer does not handle "unknown" delimiters, so I modified the code.
#include <stdio.h>
int main(void){
char s1[100] = "";
while(scanf("%99[^!£$%&*()_-+={};:'##~,.<>/?0123456789]", s1) == 1) {
getchar(); // remove the delimiter
printf("%s\n", s1);
}
}
Note I have not included characters ^ or " or [ or ] as delimiters.
If you don't have a specific delimiter (it seems to be your case), you need to parse each file line manually. You can read each line with fgets(), then parse manually(for example ignore every non-alphabetic chars).
Regards

strcmp() and strcat() sequence

On my way to hone my C skills with a C Pointers literature, I came across this code. In this problem, I am supposed to justify the output. I am familiar with working of strcat() and strcmp(). I know that strcmp() returns 0 when the two strings passed, are same.
# include <stdio.h>
# include <string.h>
int main()
{
static char str1[]="Good";
static char str2[20];
static char str3[20] ="Day";
int l;
l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));
printf("%d\n", l);
return 0;
}
The answer provided there is 0, which means that two calculated strings must be same. I tried to solve the statement in multiple steps.
First, tried strcat(str3, strcpy(str2, str1)).
'str2' gets changed to "Good", then strcat() changes str3 to `DayGood'.
My gcc compiler agrees with me so far.
Coming to strcat(str3, "good"), since str3 has been changed to DayGood already, strcat changes str3 to DayGoodgood.
Again, gcc agress with me.
int main()
{
static char str1[]="Good";
static char str2[20];
static char str3[20] ="Day";
int l;
printf("%s\n", strcat(str3, strcpy(str2, str1)));
printf("%s\n", strcat(str3, "good"));
//l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));
//printf("%d\n", l);
return 0;
}
It produces
DayGood
DayGoodgood
I again tried this variation.
int main()
{
static char str1[]="Good";
static char str2[20];
static char str3[20] ="Day";
int l;
printf("%s\n", strcat(str3, "good"));
printf("%s\n", strcat(str3, strcpy(str2, str1)));
//l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));
//printf("%d\n", l);
return 0;
}
It produces.
Daygood
DaygoodGood
In my both test cases, I get two different strings for comparison. Why is then strcmp() is producing a 0 ?
There's a quick way to get the answer without tracing all the calls: both arguments to the strcat are returned from strcpys with the first arg str3, and since strcpy returns its first arg, that means the final call is strcmp(str3, str3) which of course will be 0 no matter what weird manipulations have been done on it.
In response to the updated question, try this and see if you get enlightened:
#include <stdio.h>
#include <string.h>
int main(void)
{
static char str1[]="Good";
static char str2[20];
static char str3[20] ="Day";
char *first, *second;
printf("str3 = %p => %s\n", (void *)str3, str3);
first = strcat(str3, strcpy(str2, str1));
printf("first strcat returned %p => %s\n", (void *)first, first);
printf("and now str3 = %p => %s\n", (void *)str3, str3);
second = strcat(str3, "good");
printf("second strcat returned %p => %s\n", (void *)second, second);
printf("and now first = %p => %s\n", (void *)first, first);
printf("and now str3 = %p => %s\n", (void *)str3, str3);
printf("Is it any surprise that strcmp(first,second) = %d?\n",
strcmp(first,second));
return 0;
}
Whichever order the compiler chooses to compute the arguments to strcmp, strcat always returns its first argument.
Therefore in essence here's what happens:
... // execute strcat(str3, strcpy(str2, str1)) and strcat(str3, "good")
l = strcmp(str3, str3);
It returns 0 because both parameters:
strcat(str3, strcpy(str2, str1))
and
strcat(str3, "good")
actually return the same thing: the memory address assigned to str3. So, strcmp returns 0 because it's comparing the variable str3 with itself.
The fact that strcat is always returning the first argument passed to it make always your expression true. here is the explanation :
strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));
// ^^^^ ^^^^
// become
strcmp( str3, str3 );
So strcmp return 0 by comparing the variable to itself.
You should know that this kind of expression is not very good because it makes the code less understandable and it can lead to undefined behavior faster than you could imagine ...
strcmp gets two pointers to strings as its arguments:
l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));
1st step:
l = strcmp(str3, strcat(str3, "good"));
Here str3 points to the string DayGoodgoodGood.
2nd step:
l = strcmp(str3,str3 );
Now str3 points to the string DayGoodgoodGoodgood.
This will return 0 no matter what str3 points to. Since addresses are same strcmp shouldn't even compare for optimization; just returns 0.
strcatreturns its first arg, that's why!

Find string in text file in C

I'm trying to search a text file using C for a string of characters that will always be in a specific place. Specifically I'm looking for three sequential dashes. When it finds the three dashes it should return the line on which it was found. It should then continue to the next line and continue searching for the three sequential dashes until it reaches the end of the file. Each time is should print the line number.
This is what I have so far:
int main() {
FILE *f;
char inName[80];
printf("Read text from: ");
scanf(" %79[^\n]s\n", inName);
f = fopen(inName, "r");
if (f == 0) printf("ERROR: Cannot open file %s for reading.\n", inName);
int lineNumber = 0;
for(;;) {
char line[127];
fgets(line, 127, f);
if (!feof(f)) {
lineNumber++;
} else {
break;
}
double lf;
int d, d1;
char s[30];
char s1[4];
sscanf(line, " %d, %s, %s, %s, %s, %d, %d, %lf",
&d, &s, &s, &s, &s, &d, &s1, &lf);
if (s1 == "---") {
printf("%d\n", lineNumber); // what line
}
}
fclose(f);
return(0);
}
This code runs but does not print anything. Could anyone show how to get this done? Thanks :)
if (s1 == "---")
You're comparing strings the wrong way, you should use strcmp()
follow this example
http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1057537653&id=1043284385
This is not how to compare strings in C:
if (s1 == "---")
as is comparing the address of s1 with the address of the string literal "---".
Use strcmp():
if (strcmp(s1, "---") == 0)
{
Always check the return value of sscanf() to ensure the variables have actually been assigned a value before attempting to use them. The , comma character is not treated as delimiter when processed with "%s" format specifier, only whitespace is used as delimiter. To prevent the consumption of the , use a scan set, similar to how you have done earlier in the program (note corrections to sscanf() arguments):
if (sscanf(line,
" %d, %29[^,], %29[^,], %29[^,], %29[^,], %d, %3[^,], %lf",
&d, s, s, s, s, &d, s1, &lf) == 8)
{
}
You cannot compare char[] with ==. Use strcmp instead.
if( strcmp(s1, "---") == 0 )

C strtok seperator returns → ( at end

I have written a program that i want to input for example "11:12" to and then get "11" and "12" back. This is my code:
#include<stdio.h>
#include <string.h>
#include <conio.h>
int main(void)
{
char s[] = "";
char seperator[] = ":";
char *ch;
while (1)
{
scanf("%s", &s); //scanf("%s", &s);
if (s == -1) break;
char *result = NULL;
result = strtok(s, seperator);
while( result != NULL ) {
printf( "result is \"%s\"\n", result );
result = strtok( NULL, seperator );
}
fflush(stdout);
}
return 0;
}
but when i input "11:12", this is my output:
result is "11"
result is "12→ ("
How can i get rid of the last "→ ("?
You are not allocating any memory for your "s" array. Try it out like this:
char s[128] = "";
Plus, you are doing a double indirection on scanf with parameter &s, it is not necessary since "s" will be decayed to a pointer as a parameter to the function.
Try it like this:
scanf("%s", s);
You are defining s to be a string of length 0
char s[] = "";
So when you're reading into a string of length 0 with your scanf(), bad things will happen. Assign it some memory:
char s[100];
Also, you don't need the & in your scanf(). Just scanf("%s", s) will do.
And while we're at it, what is this trying to do?
if (s == -1) break;
Because that doesn't work... if you want to check if a "-1" was entered you need to use something like strcmp:
if (strcmp(s,"-1") == 0) break;
Your code has undefined behaviour.
char s[] = "";
With this line, you are declaring an array of chars with length 1 which means effectively you can store only null. So when you read input, you are overflowing s thus invoking UB.
You can also get rid of &s in the scanf as array name is same as its address.
Another issue is:
if (s == -1) break;
s is an array and hence it's address can't be -1. This comparison doesn't make sense.

Resources