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;
}
Related
This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 6 months ago.
I know that the program should put string2 and string1 after the string3, but I don't know where the problem is.
#include <stdio.h>
char* f(char *p1, char *p2, char *p3)
{
char* tp1 = p1;
char* tp2 = p2;
char* tp3 = p3;
while (*tp1)
tp1++;
while (*tp2)
tp2++;
while (tp1>p1)
*tp3++ = *--tp1;
while (tp2>p2)
*tp3++ = *--tp2;
*tp3=0;
return p3;
}
int main(void)
{
char* string1="abcd";
char* string2="efg";
char* string3="\0";
char* ris=f(string1,string2,string3);
printf("%s\n", ris);
}
The function tries to concatenate two strings in the reverse order and store the result in a character array.
However there is a problem because there is passed a string literal as the destination array to the function
char* string3="\0";
that may not be changed. Any attempt to change a string literal results in undefined behavior.
Instead you should write for example
char string3[8];
That is you need to pass a large enough array that can accommodate two concatenated strings: string1 and string2.
Also the function should be declared at least like
char* f(const char *p1, const char *p2, char *p3);
That is the passed string except of the result array are not changed within the function.
Here is your updated program. I changed the order of parameters in the function and renamed it.
#include <stdio.h>
char * reversed_concatenation( char *s1, const char *s2, const char *s3 )
{
char *p1 = s1;
const char *p2 = s2;
while ( *p2 ) ++p2;
while ( p2 != s2 )
{
*p1++ = *--p2;
}
const char *p3 = s3;
while ( *p3 ) ++p3;
while ( p3 != s3 )
{
*p1++ = *--p3;
}
*p1 = '\0';
return s1;
}
int main( void )
{
const char *string1 = "abcd";
const char *string2 = "efg";
char string3[8];
puts( reversed_concatenation( string3, string1, string2 ) );
}
The program output is
dcbagfe
In this function for example this for loop
const char *p2 = s2;
while ( *p2 ) ++p2;
finds the end of the first concatenated string and then this for loop
while ( p2 != s2 )
{
*p1++ = *--p2;
}
writes the string in the reverse order in the result character array.
The same operations are done with the second concatenated string.
this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.
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.
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.
I'm trying to self-study C using C Primer Plus from Stephen Prata and one of the end-of-chapter exercises is to "Write a function that replaces the contents of a string with the string reversed.". This is a chapter on character strings with a good dose of pointers. I'm trying to use pointers as much as possible so I can better understand, but I'm stuck.
My problem is that when I print the value of the return pointer in main, it is garbled.
When I use gdb(just learning how to use that too), I can see that the memory address returned from my function is the same address that was used in the function and it's getting assigned to my pointer in main okay as far as I can tell.
I've tried so many things, what am I missing? FWIW I have not learned about malloc yet in the book, though I see it referenced on various www pages I've frequented trying to better understand C.
$ cc -o exercise8 exercise8.c && ./exercise8
This is s1 before: abcd
This is s2 in function: dcba
This is s3 after: d`!
/* A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
char *str_rev(char * string);
int main(void)
{
char * s1 = "abcd";
char * s3;
printf("This is s1 before: %s\n", s1);
s3 = str_rev(s1);
printf("This is s3 after: %s\n", s3);
}
char *str_rev(char * string)
{
char ar3[5];
char * s2;
int len = 0;
s2 = ar3;
len = (strlen(string) - 1);
string = string + len;
while ( len >= 0 )
{
*s2 = *string;
len--;
string--;
s2++;
}
s2++;
*s2 = 0;
s2 = s2 - 5;
printf("This is s2 in function: %s\n", s2);
return s2;
}
$ gdb exercise8
GNU gdb (GDB) 7.1-ubuntu
Reading symbols from exercise8...done.
(gdb) break 12
Breakpoint 1 at 0x804844a: file exercise8.c, line 12.
(gdb) break 40
Breakpoint 2 at 0x80484d9: file exercise8.c, line 40.
(gdb) run
Starting program: exercise8
This is s1 before: abcd // My original string.
This is s2 in function: dcba // Good, my reversed string while in the function.
Breakpoint 2, str_rev (string=0xbffff043 "dcba") at exercise8.c:40
40 return s2;
(gdb) print s2
$1 = 0xbffff043 "dcba" // Location of pointer s2.
(gdb) continue
Continuing.
Breakpoint 1, main () at exercise8.c:12
12 printf("This is s3 after: %s\n", s3);
(gdb) print s3
$2 = 0xbffff043 "dcba" // Back in main same pointer as s2 from function.
(gdb) step
This is s3 after: d`Q // Line 12 executed. Output garbled.
14 }
(gdb)
You're returning a pointer to a local variable, (automatic variable to speak in ISO standard terms,) which is allocated on the stack, as soon as you return from your function that memory is released leaving you with a dangling pointer pointing to memory that may or may not still contain the string you put there, it depends entirely on circumstances. You should provide the output buffer as a function argument, or allocate it with malloc, or in C++ with new.
edit; added some example code
void reverse(const char* s1, char* s2) {
const int l = strlen(s1);
const char* p = s1 + l - 1;
do {
*s2++ = *p;
} while (p-- != s1);
*s2 = 0;
}
int main() {
// some code here
char s1[5] = "abcd";
char s2[5] = "";
reverse(s1, s2);
// some more code here
return 0;
}
or
char* reverse(const char* s) {
const int l = strlen(s);
char* rs = malloc(l+1);
const char* p = s + l - 1;
do {
*rs++ = *p;
} while (p-- != s);
*rs = 0;
return rs - l;
}
int main() {
// some code here
char s1[5] = "abcd";
char* s2 = reverse(s1);
// some more code here
free(s2);
return 0;
}
char ar3[5];
char * s2 = ar3;
The above code will make s2 points to a character string on the stack. This ar3 variable will be deleted once your function finishes.
You should output to some variable that you have pre-allocated. Modify it as follow
int main(void)
{
char * s1 = "abcd";
char s3[5];
printf("This is s1 before: %s\n", s1);
str_rev(s1, s3);
printf("This is s3 after: %s\n", s3);
}
void str_rev(char * string, char * s2)
{
........
// don't return
// Also assign the last character with the NULL terminator
ar2[strlen(string)] = '\0';
}
Of course, once you get to the chapter regarding malloc, you can allocate the necessary memory for s3 depending on the length of s1. Until then, read on and have fun.
The problem description sounds like you can just reverse the string in place. Keep it simple.
void reverse_range(char *first, char *last) // [first, last)
{
for (; first != last && first != --last; ++first)
{
char temp = *first; *first = *last; *last = temp;
}
}
void reverse(char *str)
{
reverse_range(str, str + strlen(str));
}
int main()
{
char text[] = "0123456789";
printf("before: %s\n", text);
reverse(text);
printf("after : %s\n", text);
}
s2 points to your local ar3 array. Therefore when str_rev returns, it is no longer valid to look at the memory where ar3 was via s2. Now s2 is called a dangling pointer, and this is one of the huge pains in learning to use C pointers correctly.
For a simple solution that doesn't use malloc and meets the exercise requirement of "replaces the contents of a string", try copying the result into the function argument pointer (the original string; but be careful since your current code has since changed the pointer string). You know this pointer points at memory with enough characters and isn't local to your function.
Part of the problem is that you can't actually "replace the contents of a string with the string reversed" when you are dealing with string literals, ie. strings delcared in the form char * s1 = "abcd";
Without using literals, I made a relatively easy to understand recursive example:
/* A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
void str_rev(char * string);
int main(void)
{
char s1[] = "abc";
char s2[] = "even";
char s3[] = "quodd";
printf("This is s1 before: %s\n", s1);
str_rev(s1);
printf("This is s1 after: %s\n", s1);
printf("This is s2 before: %s\n", s2);
str_rev(s2);
printf("This is s2 after: %s\n", s2);
printf("This is s3 before: %s\n", s3);
str_rev(s3);
printf("This is s3 after: %s\n", s3);
return 0;
}
void str_rev(char * string) {
//Store the first char of the string locally
char firstChar = string[0];
//Store the last char of the string locally
int lastCharPos = strlen(string)-1;
char lastChar = string[lastCharPos];
//Shorten the string (temporarily)
string[lastCharPos] = '\0';
if (string[1] != '\0') {
//Call on the now shortened string, eg.
//"abc" becomes "b"
//"even" becomes "ve"
//"quodd" becomes "uod"
str_rev(string+1);
}
//Swap the first and last characters
string[0] = lastChar;
string[lastCharPos] = firstChar;
}
On my system the output is as follows:
This is s1 before: abc
This is s1 after: cba
This is s2 before: even
This is s2 after: neve
This is s3 before: quodd
This is s3 after: ddouq
#include <stdio.h>
#include <string.h>
void my_strrev(char* begin){
char temp;
char* end;
end = begin + strlen(begin)-1;
while(end>begin){
temp = *end;
*end = *begin;
*begin = temp;
end--;
begin++;
}
}
main(){
char string[]= "foobar";
my_strrev(string);
printf("%s", string);
}