Passing char pointers between functions - Are both ways equal? - C - 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.

Related

delete leading characters before a string in C (concept question)

I’m learning C, dealing with strings and pointers. An exercise calls for deleting all leading characters (‘X’ in this case) before a string. The called function must accept a string, i.e. a pointer to a char. I have found multiple ways of doing this by searching, but I do not understand why the following code does not work...what concept am I missing?
//delete all leading X characters by passing pointer to a string
#include <stdio.h>
#include <string.h>
void delChar(char* str)
{
char* walker; //declare pointer
walker = str; //point to beginning of passed string
while(*walker == 'X') walker++; //move pointer past amy leading 'X'
printf("\nwalker string is now: %s", walker); //prints "Test" as expected
str = walker; //set str pointer to walker
printf("\nstr string is now: %s", str); //prints "Test" as expected
return;
}
int main()
{
char* myStr = "XXXXXXXXXXXXTest";
printf("Before function call: %s", myStr); //prints "XXXXXXXXXXXXTest" as expected
delChar(myStr); //pass pointer to the string
printf("\nAfter function call: %s", myStr); //WHY DOES THIS print "XXXXXXXXXXXXTest" ?
return 0;
}
There are multiple ways in which characters can be deleted from a string, and it is not clear which you want.
In C, memory contents cannot be “deleted.” Memory is formed of bytes, and bytes hold values. When we have a string, it exists in a certain place in memory, and the bytes of the string cannot be made to go away.
Three ways to delete characters from a string are:
Given the start address of the string, return the address of the desired part of the string.
Given a pointer to the start of the string, update the pointer to point to the desired part of the string.
Move characters from later in the string to earlier.
Here are sample implementations:
#include <stdio.h>
/* Deletion method 0: Find the first character that is not an "X" and
return its address.
*/
static char *DeleteMethod0(char *string)
{
for (char *p = string; ; ++p)
if (*p != 'X')
return p;
}
// Deletion method 1: Update the pointer to the start of the string.
static void DeleteMethod1(char **string)
{
while (**string == 'X')
++*string;
}
// Deletion method 2: Move characters.
static void DeleteMethod2(char *string)
{
// Find the point where we stop deleting.
char *source = string;
while (*source == 'X')
++source;
// Copy the undeleted part of the string to the start.
while (*source)
*string++ = *source++;
*string = '\0';
}
int main(void)
{
char *string = "XXXXXXXXXXXXTest";
char buffer[] = "XXXXXXXXXXXXTest";
printf("The string is %s.\n", string);
printf("The buffer contains %s.\n", buffer);
char *after = DeleteMethod0(string);
printf("The string after deletion by getting new address %s.\n", after);
DeleteMethod1(&string);
printf("The string after deletion by updating the pointer is %s.\n", string);
DeleteMethod2(buffer);
printf("The buffer after deletion by moving characters is %s.\n", buffer);
}
Another option would be to make a new copy of the desired part of the string, in memory either supplied by the caller or allocated by the deletion routine.
For starters the function should be declared like
char * delChar( char *str );
The function parameter str is a local variable of the function. So this assignment
str = walker;
does not change the pointer myStr declared in main. This pointer is passed to the function by value. That is the function deals with a copy of the pointer. And the assignment does not change the original pointer myStr. It changes only its local variable str that was initialized by a copy of the value of the pointer myStr.
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior. But you need indeed to change the passed string as at least followed from your assignment
delete leading characters before a string in C
That is the task is not to find the pointer that points to the first character that is not equal to 'X'. You need to remove leading characters equal to 'X' from a string.
In main you need to declare a character array instead of a pointer to a string literal as for example
char myStr[] = "XXXXXXXXXXXXTest";
The function itself can be defined the following way
char * delChar( char *str )
{
char *walker = str;
while ( *walker == 'X' ) ++walker;
if ( walker != str ) memmove( str, walker, strlen( str ) + 1 - ( walker - str ) );
return str;
}
And in main it is enough to write
printf("After function call: %s\n", delChar( myStr ) );
Here is a demonstration program
#include <stdio.h>
#include <string.h>
char * delChar( char *str )
{
char *walker = str;
while (*walker == 'X') ++walker;
if (walker != str) memmove( str, walker, strlen( str ) + 1 - ( walker - str ) );
return str;
}
int main( void )
{
char myStr[] = "XXXXXXXXXXXXTest";
printf( "Before function call: %s\n", myStr );
printf( "After function call: %s\n", delChar( myStr ) );
}
The program output is
Before function call: XXXXXXXXXXXXTest
After function call: Test
The function will be more flexible if to declare a second parameter that will specify a character that should be deleted from the beginning of a string. For example
char * delChar( char *str, char c )
{
if ( c != '\0' )
{
char *walker = str;
while (*walker == c) ++walker;
if (walker != str) memmove( str, walker, strlen( str ) + 1 - ( walker - str ) );
}
return str;
}
In this case the function is called like
printf( "After function call: %s\n", delChar( myStr, 'X'));
str variable in function delChar will created over stack and store address you have passed and will be destroyed when function returns
void delChar(char* str) // str variable will created over stack and store address you have passed and will be destroyed when function returns
{
char* walker; //declare pointer
walker = str; //point to beginning of passed string
while(*walker == 'X') walker++; //move pointer past amy leading 'X'
printf("\nwalker string is now: %s", walker); //prints "Test" as expected
str = walker; //set str pointer to walker
printf("\nstr string is now: %s", str); //prints "Test" as expected
return;
}
After the return str in main will still point to start of the string.
you need to return the address and store
you can track count using counter and return the count Like below
#include<stdio.h>
int delChar(char* str)
{
int count = 0;
while(*str++ == 'X')
count++; // increment the count when x found
printf("\nwalker string is now: %s", str+count);
return count;
}
int main()
{
char* myStr = "XXXXXXXXXXXXTest";
int count;
printf("Before function call: %s", myStr);
count = delChar(myStr);
printf("\nAfter function call: %s", myStr+count);
return 0;
}
Thank you for the thoughtful replies and comments. I infer that this has basically been a question about pointers; that is. modifying a string without needing to return a pointer from a function call. I simplified the example code question for the benefit of those who might be learning as well, with comments (see below). Let me know if I’m off base here...
#include <stdio.h>
#include <stdlib.h>
void func(char** str) //note POINTER-TO-POINTER parameter!
{
printf("\nintial func str: %s", *str); //note dereference before str; prints "FULL TEXT"
*str += 5; //increment pointer five spaces to right to modify the string
printf("\nafter func str: %s", *str); //note dereference before str; prints "TEXT"
}
int main()
{
char* myStr = "FULL TEXT"; //need to initialize string with pointer variable
//char myStr[] = "FULL TEXT"; //initializing string as array will not work for this example!
printf("\n...before MAIN func call: %s", myStr); //prints "FULL TEXT"
/*pass ADDRESS of pointer variable instead of pointer variable itself, i.e. func
parameter needs to be a pointer-to-a-pointer...this is essentially passing by REFERENCE
instead of by VALUE (where a copy would get clobbered when returning to main)*/
func(&myStr); //note ADDRESS symbol, i.e. address of pointer variable
printf("\n...after MAIN func call: %s", myStr); //prints "TEXT", modified string remains after func call
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.

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!

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