strcmp() and strcat() sequence - c

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!

Related

Taking multiple strings through scanf

When I try to use scanf() to read one string of chars, everything works.
In the code below, I read two strings of chars, but if I input "abcde abcde" (arbitrary letters), printf() prints " is your character".
int main(){
char A[5], B[5];
scanf("%s %s", A,B);
printf("%c is your character", A[0]);
}
What am I doing wrong?
You are typing one string of length 5 (+1 with \0) and try to put it in a char table of size 5, which is an undefined behavior.
If you want to put “abcde” in both A and B, you need to increase the size of A and B to at least 6.
As #pmg pointed out already, the char array has to be long enough to have the null-terminator at the end of it, thus abcde abcde doesn't work, but abcd abcd works. If you would like to solve this statically, literally just stretch the size of the array buy how much you need:
char A[40], B[40];
However, if you really insist on getting dynamic allocation, you could use getline(), then malloc on some char* of the length of your input string (worst case scenario), and then use sscanf to split your input stringo to A and B.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* I = NULL;
char* A;
char* B;
size_t len = 0;
if (getline(&I, &len, stdin) != EOF)
{
A = (char*)malloc(len + 1);
B = (char*)malloc(len + 1);
sscanf(I, "%s %s", A, B);
printf("%c is your character", A[0]);
free(A);
free(B);
}
free(I);
return 0;
}

C: Realloc invalid pointer?

This is my task from school:
Write a function ​insertString ​that inserts the string s2 into s1 at index n.s1 has been allocated using malloc and should be resized (the function is void again).
The program gave me a NULL on PC and when I switched to the phone the compilor said my realloc has a invalid pointer. But I really don't know what I did wrong.
Here is the code:
void insertString(char *str1, char *str2, int n){
int lengStr2=strlen(str2);
printf("%d %d ", lengStr2,n);
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
str1=(char*)realloc(str1,lengStr2+n+1);
if (str1==NULL){
printf("Error\n");
free(str1);
return -1;
}
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
memcpy(str1+n,str2,lengStr2+1);
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
}
void testInsertString( char *str2, int n, char *expect){
char*str1=(char*)malloc(3*sizeof(char));
str1="hoi";
printf("\nstr1= %s, str2: %s, n: %d ",str1,str2,n);
insertString(str1,str2,n);
printf("--> result:%s --> ",str1);
(strcmp(str1,expect)==0)?printf("Success"): printf("Failure");
free(str1);
printf("\nIs Free\n");
}
Here the output:
str1= hoi, str2: Hallo, n: 1 5 1
str1= hoi, str2: Hallo, n: 1 Error
--> result:hoi --> Failure
Is Free
Process returned 0 (0x0)
Please if you know what I did wrong can you show me the correct version? Even so I have the problem that I can't right a program right just by reading a text, I need to see how it should be written. So I need to see the right result to learn from the mistake ^^" (that's why some stuff in school is for me really hard). Thanks in advance ^^
char *str1 = malloc(3*sizeof(char)); /* Allocate memory */
str1="hoi"; /* Discard the only reference to the allocated memory */
The above two lines are similar in spirit to:
int x = 5;
x = 7;
You need to copy the string "hoi" into the newly allocated memory, and you need to allocate at least 4 bytes to hold the string "hoi". For example:
char *hoi = "hoi";
char *str1 = malloc(strlen(hoi) + 1);
if( str1 == NULL ){
perror("malloc");
exit(EXIT_FAILURE);
}
sprintf(str1, "%s", hoi);
Here is a fixed version :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// Changing the signature to return the reallocated ptr would be safer
char * insertString(char *str1, char *str2, int n){
int lengStr2=strlen(str2);
//because str1 could differ from the received ptr after reallocation
str1=(char*)realloc(str1,lengStr2+n+1);
if (str1==NULL){
printf("Error\n");
return NULL;
}
strcpy(str1+n,str2);
return str1; // So we return the new ptr to the caller
}
void testInsertString( char *str2, int n, char *expect){
char*str1=(char*)malloc(6*sizeof(char)); // The null termination must be counted
strcpy(str1, "Hello"); // You should use strCpy here instead of =
str1 = insertString(str1,str2,n); // Refreshes the ptr
printf("\n--> result:%s --> ",str1);
(strcmp(str1,expect)==0)?printf("Success"): printf("Failure");
free(str1);
}
int main() {
testInsertString(" World", 5, "Hello World"); // --> result:Hello World --> Success
return 0;
}

Why there is a garbage value is coming after strrev in C?

There is my friend's code and I'm looking at that.
It's a simple example of using string's function and I feel that's not simple.
The problem is part (5).
This is code.
#include <stdio.h>
#include <string.h>
void reverse(char *str1, char *str2) {
str1 = strrev(str2);
printf("%s\n\n", str1); //**It's a test.**
}
int main() {
char str1[100];
char str2[100];
char str3[100];
char str4[100];
char temp[100];
int len1, len2, len3, len4;
//(1) use scanf()
printf("(1) str1 : ");
scanf("%s", &str1);
printf(" str2 : ");
scanf("%s", &str2);
//(2) exchange, print()
strcpy(temp, str1);
strcpy(str1, str2);
strcpy(str2, temp);
printf("(2) str1=%s str2=%s\n", str1, str2);
printf("len1=%d len2=%d\n", strlen(str1), strlen(str2));
//(3) copy, print()
strcpy(str3, str2);
printf("(3) str3=%s\n", str3);
//(4) strcat()
strcat(str3, " ");
strcat(str3, str1);
strcat(str3, " My name is Elsa");
printf("(4) str3=%s\n", str3);
printf("len3=%d\n", strlen(str3));
//(5) reverse(str4, str3), print str4
reverse(str4, str3);
printf("(5) str4=%s\n", str4); //**I don't know here**
printf("len4=%d\n", strlen(str4));
return 0;
}
and this is the result.
Why there is a garbage value?
In this call
reverse(str4, str3);
the array str4 is passed by value. So the expression str4 used as an argument is converted to a temporary pointer to the first element of the array.
Thus the function reverse deals with this temporary object that is used as an initializer of the parameter of the function.
Changing this parameter (local variable of the function) does not influence on the content of the original array. It stays unchanged.
That is in this statement within the function
str1 = strrev(str2);
in fact the pointer str2 is assigned to the pointer str1. The string pointed to by the pointer str2 will be changed. As for the pointer str1 then it now points to the same string as the pointer str1 and it will not be alive after exiting the function.
The function could be defined for example the following way if you want to change the string pointed to by the first parameter of the function
void reverse(char *str1, char *str2) {
strcpy( str1, strrev(str2) );
printf("%s\n\n", str1); //**It's a test.**
}
However the function does not make great sense because it reverses two strings simultaneously.
If you wanted to copy the content of the string pointed to by the second parameter of the function into the array pointed to by the first parameter of the function then the function definition can look like
void reverse( char *str1, const char *str2 )
{
strcpy( str1, str2 );
strrev( s1 );
printf("%s\n\n", str1); //**It's a test.**
}
In this case the string pointed to by the pointer str2 will be unchanged while the array pointed to by the pointer str1 will get the reversed string pointed to by the pointer str2.
Your function declaration should be instead as follows,
void reverse(char **str1, char *str2)
thereby not wanting to do operation just locally.

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.

strcmp misbehave with 2 same strings

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.)

Resources