1.C code for swapping two strings stored in character arrays.
#include<stdio.h>
/* Swaps strings by swapping pointers */
void swap1(char **str1_ptr, char **str2_ptr)
{
char *temp = *str1_ptr;
*str1_ptr = *str2_ptr;
*str2_ptr = temp;
}
int main()
{
char str1[10] = "geeks";
char str2[10] = "forgeeks";
swap1(&str1, &str2);
printf("str1 is %s, str2 is %s", str1, str2);
getchar();
return 0;
}
2.C code for swapping two strings stored in read only memory.
#include<stdio.h>
/* Swaps strings by swapping pointers */
void swap1(char **str1_ptr, char **str2_ptr)
{
char *temp = *str1_ptr;
*str1_ptr = *str2_ptr;
*str2_ptr = temp;
}
int main()
{
char *str1 = "geeks";
char *str2 = "forgeeks";
swap1(&str1, &str2);
printf("str1 is %s, str2 is %s", str1, str2);
getchar();
return 0;
}
These two are codes for swapping two strings (one string stored in stack,other in read only memory).
Will they work the same?
It is said that first code will not work properly.
If so, Why?
The first example will not work because you are not really passing pointers to pointers in the call to the swap1 function, you are passing pointers to arrays.
The type of the expression &str1 is not char**, it is char (*)[10]. It is a very big difference, and that will lead to all kind of problems when attempting to dereference those pointers and swap them.
Related
i know this is a very simple question but i'm new and a bit down here.. i'm learning more about how to use functions, and i can get this to work if it was simply in main, or i can use another way, but i'm trying to solve it using strcpy(), and i dont want to change the main, everythijg should be in the function, any help is very much appreciated.
char swap_char(char *s1, char *s2) {
printf("before swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
char temp[50];
strcpy(temp, s1);
strcpy(s1, s2);
strcpy(s2, temp);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
}
main() {
swap_char("please","work");
}
"please" has 7 characters (including the terminator), but "work" only has 5 characters. There is enough space for the first string to contain "work", but the second string does NOT have enough space to contain "please" in it.
Your code has literal strings "please" and "work", which means they are very likely in READ ONLY memory, and cannot be changed or overwritten.
Fixing these two problems I get:
char swap_char(char *s1, char *s2) {
printf("before swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
char temp[50];
strcpy(temp, s1);
strcpy(s1, s2);
strcpy(s2, temp);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
}
int main() {
char alpha[20] = "please"; // Declare space 20: MORE than enough space for either string
char beta[20] = "work"; // Also, use a local array, which is NOT read-only, and can be changed.
swap_char(alpha,beta);
return 0;
}
Output
Success #stdin #stdout 0s 5524KB
before swapping : swap_char("please", "work")
After swapping : swap_char("work", "please")
The first step is reading the docs to see how it can be used and see if they have any helpful examples.
The first issue here is we don't know if we will have enough space to complete this task. Instead we can malloc space dynamically to make sure we don't run into issues.
// We don't need to return a char
void swap_char(char *s1, char *s2) {
printf("before swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
// Allocate on the heap so we know we will never run out of space on a long input
char temp = malloc(strlen(s1) + 1);
strcpy(temp, s1);
strcpy(s1, s2);
strcpy(s2, temp);
// Free temporary buffer
free(temp);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", s1, s2);
}
However, there is a bigger problem here. We don't know if both pointers have enough memory allocated. This is why this approach is not all that practical. Also by passing the string pointers directly instead of using a pointer to a buffer on the stack or heap risks attempting to mutate read-only memory. String constants are loaded along with the assembly instructions in each function into read-only memory on most modern systems. This is good since it prevents a malicious actor or undefined behavior from modifying the function assembly.
char *a = "please";
char *b = "work";
// Create new buffers with the required space to use instead
unsigned int buffer_len = imax(strlen(a), strlen(b)) + 1;
char *a_buffer = malloc(buffer_len);
char *b_buffer = malloc(buffer_len);
// Copy the input strings into our new buffers
strcpy(a_buffer, a);
strcpy(b_buffer, b);
// Finally swap the buffers
swap_char(a_buffer, b_buffer);
As you can see, it isn't very practical but it is possible. A more practical approach is to just swap the pointers held by variables.
void swap_strings(char **s1, char **s2) {
char *temp = *s1;
*s1 = *s2;
*s2 = temp;
}
char *a = "please";
char *b = "work";
printf("Before swapping : swap_char(\"%s\", \"%s\")\n", a, b);
swap_strings(&a, &b);
printf("After swapping : swap_char(\"%s\", \"%s\")\n", a, b);
This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Closed 1 year ago.
void fun1(char *s1, char *s2) {
char *temp;
temp = s1;
s1 = s2;
s2 = temp;
}
int main () {
char *str1 = "Hello", *str2 = "there!"
fun1(str1, str2);
printf("%s %s", str1, str2);
return 0;
}
Given the code above, from my understand we pass the pointers by value, so if for example the values are str1 = 1000, str2 = 2000, fun1 switches them around, so str1 = 2000, str2 = 1000.
So when we are trying to print them, we should get "there! Hello", but the answers says that it prints "Hello there!" and I don't understand why.. by switching them around str1's value should be the memory adress of the first character of "there!" and str2 of the first character of "Hello"..
I feel like I'm missing something important..
The pointers are passed by value, so switching values of s1 and s2 will not affect str1 and str2.
If you want functions modify what caller specifies, you should pass pointers to what should be modified like this:
#include <stdio.h>
void fun1(char **s1, char **s2) {
char *temp;
temp = *s1;
*s1 = *s2;
*s2 = temp;
}
int main (void) {
char *str1 = "Hello", *str2 = "there!"
fun1(&str1, &str2);
printf("%s %s", str1, str2);
return 0;
}
I'm trying to swap two strings passed in as char pointers.
In debugging, I get the right answers at the end of the called function, but returning the values after the function ends returns the same values as passed in. Here is the code
#include <stdio.h>
int main(int argc, char const *argv[]) {
char *s1, *s2;
s1 = "12345678";
s2 = "87654321";
printf("s1 is %s\n", s1);
printf("s2 is %s\n", s2);
strswap(s1, s2);
printf("s1 is now %s\n", s1);
printf("s2 is now %s\n", s2);
}
and the code for the function itself
#include <stdio.h>
void strswap(char *s1, char *s2){
char *temp;
temp = s1;
printf("temp: %s\n", temp);
s1 = s2;
printf("s1: %s\n", s1);
s2 = temp;
printf("s1: %s\n", s1);
printf("s2: %s\n", s2);
printf("temp: %s\n", temp);
}
I order to swap strings, first of all you can't just use constant string literals since they are immutable. Assigning string literal to char * is considered bad practice unless you properly know what you're trying to achieve. Read this link and this also. You should use statically/dynamically allocated strings.
As other people said, you're passing the character pointers by value, so any changes you make in strswap() would not be reflected in main function. Since some local variables are modified and they get destroyed when control goes out of those functions. You should either pass char ** like in one of the mentioned answers. I would recommend to use statically allocated strings and use strcpy for string copy operations like this:
#include <stdio.h>
#include <string.h>
#define MAX_SIZE 1000
void strswap(char *s1, char *s2){
char tempStr[MAX_SIZE];
strcpy(tempStr, s1);
strcpy(s1, s2);
strcpy(s2, tempStr);
}
int main(int argc, char const *argv[]) {
char aString1[MAX_SIZE] = "Rohan", aString2[MAX_SIZE] = "Rohit";
printf("s1 is %s\n", aString1);
printf("s2 is %s\n", aString2);
strswap(aString1, aString2);
printf("s1 is now %s\n", aString1);
printf("s2 is now %s\n", aString2);
return 0;
}
C uses pass-by-value for function argument passing.
Here, the pointers themselves are passed by value, so any changes made to the pointers (for example, assigning values to them), will not be reflected to the actual arguments in the caller. However, if any change is made to the value stored at the memory location pointed to by the pointers, that would be reflected to the actual arguments used to call the function from the caller.
So, to change a pointer value itself, you need to pass a pointer to the pointer.
You're using string literals to initialize the pointers, you can't swap those strings with the function prototype you showed.
Assuming the string initialization is a mistake, we can do the swap without changing the function's prototype, by copying the actual characters around. This requires that the strings have equal length, otherwise the longer one can't be copied to the space used by the shorter one.
Here's an attempt:
void swap_strings(char *a, char *b)
{
const size_t al = strlen(a);
const size_t bl = strlen(b);
if(al != bl)
return;
for(size_t i = 0; i < al; ++i)
{
const char t = a[i];
a[i] = b[i];
b[i] = t;
}
}
I changed the function's name, I have a vague recollection that you're not supposed to add functions with names beginning with str, that's reserved.
Note: this requires that the strings be writable, so you can't use it on string literals. You have to have proper buffers (or arrays) like this:
char a[] = "foo";
char b[] = "bar";
swap_strings(a, b);
printf("'%s' and '%s'\n", a, b);
This will print 'bar' and 'foo'.
My plain C is a bit rusty, and I currently try to figure out why the first works and the second doesn't.
char *returnSomething(void) {
char *s = (char *) malloc(5 + 1);
strcpy(s, "Hello");
return s;
}
void dontReturnSomething(char *dest) {
char *s = (char *) malloc (5 + 1);
strcpy(s, "Hello");
dest = malloc(strlen(s) + 1);
strcpy(dest, s);
free(s);
}
int main(int argc, char *argv[]) {
char *first = returnSomething();
char *second = NULL;
dontReturnSomething(second);
printf("first: %s | second: %s", first, second);
}
Isn't it basically doing the same thing?
To return a pointer through a parameter you need a pointer to a pointer. Declare dest as char **dest.
void dontReturnSomething(char **dest) {
char *str = "Hello";
*dest = malloc(strlen(str) + 1);
strcpy(*dest, str);
}
Call the function like this:
dontReturnSomething(&second); // pass in address of second
To be more accurate, pointers to pointers are only necessary so long as, just as in the examples above, the memory is not allocated until after you enter the function. Just wanted to say this for anyone having pointer problems and thinks any passing of pointers always requires pointers to pointers to be passed.
For example, the below example works just fine.
void dontReturnSomething(int* testint)
{
int test = 33;
*testint = test;
}
int main(int argc, char *argv[])
{
int *first = calloc(1,sizeof(int));
printf("Before: %d\n", *first);
dontReturnSomething(first);
printf("After: %d\n", *first);
return(1);
}
If you run it, you'll get 0 and 33 as expected. Of course the caveat to this is that you absolutely have to have memory allocated to the pointer being used. If you allocated memory for the pointer inside the function, then you will be assigning it a new address that would then have to be returned so that the address can persist. The below example also works just fine.
void dontReturnSomething(char* testchar)
{
char* test = "Hello World!";
strcpy(testchar,test);
}
int main(int argc, char *argv[])
{
char *hello = NULL;
hello = calloc(13, sizeof(char));
printf("Before: %s\n", hello);
dontReturnSomething(hello);
printf("After: %s\n", hello);
return(1);
}
Of course you will pretty much never know the size of a string, or more usually a buffer, ahead of time. I just think it's important to understand the subtleties of pointers.
This is a simple program to copy a string to a new string from a C programming book (Programming in C, S. Kochan). It runs fine, but there is a pointer that I do not see initialized. I'm struggling with pointers here, but I have imbedded in my coding the C golden commandment: "THOU SHALT NOT USE THY POINTERS THAT ARE NOT INITIALIZED". Here is the code:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *to, char *from);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
I was under the impression that all pointers must be initialized in the manner:
*ptr = &variable;
or risk something important in your system being overridden. But I am seeing many programs in my books that are not initializing pointers explicitly, and this makes me very uncomfortable. Please give me some tips about prudent pointer use so I don't destroy my machine, especially anything pertaining to strings. Thanks in advance all!
This confuses you - void copyString (char *to, char *from);. This is just a declaration in main. char *to and char *from in main are not in use so do not worry. The above code is as good as:
#include <stdio.h>
void copyString(char *to, char *from) //I do not see where the 'from' pointer is initilized?
{
for( ; *from != '\0'; ++from, ++to)
{
*to = *from;
}
*to = '\0';
}
int main(void)
{
void copyString (char *, char *);
char string1[] = "A string to be copied.";
char string2[50];
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
//I do not see where the 'from' pointer is initilized?
When you pass arguments like this copyString(string2, string1); - They will be copied into the args on function call of copyString(char *to, char *from). So in the first call:
copyString(string2, string1); - to = string2, and, from = string1
"A string to be copied."
from--^
And in the second call:
to = string2, and, from = "So is this."
"So is this."
from--^
string2 does not cause any problems (even though it was not initialized) since your overwriting its values (which had garbage values before).
to and from are function parameters, when the function is called, they are assigned the value of the arguments:
copyString(string2, string1);
to is assigned the value of stirng2 while from is assigned the value of string1. Note that even though string2 and string1 has type of char arrays, but they "decayed" into a pointer to the first element when passed as function arguments.
You are correct - all pointer must be initialized as you said.
When you're declaring the strings, as an array of characters as below:
char string1[] = "A string to be copied.";
char string2[50];
string1 and string2 are pointer to arrays of strings. So, they are already pointers.
When you used them in the copyString function, you are already using pointers, and the assignent is done implicitly. So:
to = string2 = &string2[0];
Here is a commented version of your code - the "from" variable has been renamed to source, and the printf's for the pointer values should illustrate the source. But suffice to say that the arguments to the copyString function are provided by the two calls to the function in your main program. The compiler generates code which takes the arguments you provide in the calls to the function with instructions to save these arguments onto the function call stack frame. Then when the function is called, these values are referenced in the function.
#include <stdio.h>
//the char pointer dest is provided as an argument
//the char pointer source is provided as an argument
char*
copyString(char *dest, char *source)
{
if(!dest) return dest;
if(!source) return dest;
printf("dest %x, source %x\n", dest, source);
//for each character in source, until *source == '\0'
for( ; *source; )
{
//assign the char at *dest into *source
//then post-increment source, dest
*dest++ = *source++;
}
//ensure the dest string is terminated
*dest = '\0';
return dest;
}
int main(void)
{
char* copyString (char *to, char *source);
char string1[] = "A string to be copied.";
char string2[50];
printf("string2 %x, string1 %x\n", string2, string1);
copyString(string2, string1);
printf("%s\n", string2);
copyString(string2, "So is this.");
printf("%s\n", string2);
return 0;
}
When you run the program, you will see the locations of the source and destination pointers provided,
$ ./copystr
string2 bff0dbe7, string1 bff0dc19
dest bff0dbe7, source bff0dc19
A string to be copied.
dest bff0dbe7, source 80485f0
So is this.