I am trying to recreate the C++ function std::string.pop_back in C, where the last non-NUL character of the input string is popped off. In the pop_back function below the variable out has the desired output of the function, but trying to reassign *string to be out makes *string be the correct value before the function closes (for example, if I were to print string* at the end of the function, it would output Hello World), but in main(), after pop_back() is called, string is output as blank. What am I doing wrong in reassigning string?
#include <stdio.h>
#include <string.h>
void pop_back(char** string) {
size_t stringLen = strlen(*string);
char out[stringLen];
strxfrm(out, *string, stringLen);
// Here *string == "Hello World!"
*string = out;
// Here *string == "Hello World"
}
int main(int argc, char* argv[]) {
char* string = "Hello World!";
printf("Initial string: %s\n", string);
pop_back(&string);
printf("After pop_back: %s\n", string);
return 0;
}
// Output:
// $ ./pop_back_test
// Initial string: Hello World!
// After pop_back:
// Expected output:
// $ ./pop_back_test
// Initial string: Hello World!
// After pop_back: Hello World
With your code
char out[stringLen];
...
*string = out;
You "return" (assign to a parameter) a pointer to a "local variable", i.e. a pointer to an object with automatic storage duration, which's life time ends at the end of the function. Accessing an object beyond its lifetime is undefined behaviour.
You probably have to dynamically allocate a new string, which you can then manipulate and use after function execution has ended. For example:
if (!(*string) || !(**string)) {
// decide what to do with NULL or empty input strings.
...
}
else {
size_t stringLen = strlen(*string);
char* out = malloc(stringLen);
memcpy(out, *string, stringLen);
out[stringLen-1] = '\0';
}
*string = out;
Don't forget to free allocated memory afterwards. BTW: if you operate on a copy, I'd suggest to return the (new) copy and leave the input pointer as is, i.e. I'd change the prototype to
char* pop_back(char* string) {
...
return out;
}
As I step through your code, the message in my debugger indicates on line...
*string = out;
...that *string is over array bounds, failing the assignment. *string points to a string literal which means among other things it cannot be modified. Attempting to modify its content will always fail.
There are several ways this can be remedied.
One way is to modify your pop_back() function to accept a char *, and return a char *, allowing you to pass in an immutable string and return the resulting string.
Suggested implementation:
char * pop_back(char *string)
{
size_t stringLen = strlen(string)+1;//add one for NULL
char *out = calloc(stringLen,1);//create space for new string
strxfrm(out, string, stringLen);
// Here *string == "Hello World!"
return out;//return string
// Here *string == "Hello World"
}
int main(int argc, char* argv[])
{
char *string1 = "Hello World!"; // source string
char *string2 = {0}; // container for local result
printf("Initial string: %s\n", string1);
string2 = pop_back(string1); // get local result
printf("After pop_back: %s\n", string2);// use local result
free(string2); // free local result
return 0;
}
Related
Once again, I have stumbled across another unexpected occurrence.
In the following code, it seems that if I use changeStr() to change a string, from the function's perspective it has changed, but it has not changed from the program's perspective.
However if I don't use changeStr() and set the string myself, it seems to work.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* set string to newStr */
void changeStr(char *string, char *newStr) {
string = realloc(string, strlen(newStr) + 1);
memcpy(string, newStr, strlen(newStr) + 1);
printf("String from function=%s\n", string);
}
int main() {
char *str = NULL;
changeStr(str, "Hello world!");
printf("String=%s\n", str);
/* set string without function */
char *test = NULL;
char *newStr = "hello world";
test = realloc(test, strlen(newStr) + 1);
memcpy(test, newStr, strlen(newStr) + 1);
printf("NewStr=%s\n", test);
free(str);
free(test);
return 0;
}
Output:
String from function=Hello world!
String=(null)
NewStr=hello world
I know that function parameters in C are duplicated into a new variable for the function, but only the pointer is duplicated - not the string itself - so what's going on here?
P.S. I am no multi-year experienced programmer, so not sure if something is wrong.
The realloc() call as you are using it creates a new object and returns the pointer to it, which gets assigned into the string local variable in changeStr().
If you want the caller function (main()) to have access to that newly allocated object, then the callee function (changeStr()) needs to pass the new pointer back to the caller (e.g. as a return value). For example:
char *changeStr(char *string, char *newStr) {
string = realloc(string, strlen(newStr) + 1);
memcpy(string, newStr, strlen(newStr) + 1);
printf("String from function=%s\n", string);
return string; // <-- return the updated string object to caller
}
int main() {
char *str = NULL;
str = changeStr(str, "Hello world!");
printf("String=%s\n", str);
I'm trying to write a void function that gets a pointer to a pointer of a string (char**) as a parameter, and changes the original char* so it pointed to another string, lets say "hello".
Below is the code I've written:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change_ptr(char **str_ptr)
{
char hello[] = "hello";
char *hello_ptr = hello;
*str_ptr = hello_ptr;
}
int main()
{
char str[] = "yay";
char *str_ptr = str;
char **ptr_to_str_ptr = &str_ptr;
change_ptr(ptr_to_str_ptr);
printf("%s\n", str);
return 0;
}
As you can see, Im getting the pointer to the pointer of the char* "yay", delivering it to the function, and in the function I'm getting the pointer to "hello", and changes *str_ptr (which is the pointer to the original string) to the pointer to hello. But when I print str at the end, it prints "yay".
What am I doing wrong?
(when I debug with printing the addresses, everything seems fine.)
This works:
#include <stdio.h>
void change_ptr(const char ** str_ptr)
{
*str_ptr = "hello";
}
int main()
{
char str[] = "yay";
const char * str_ptr = str;
const char ** ptr_to_str_ptr = &str_ptr;
change_ptr(ptr_to_str_ptr);
printf("%s\n", str_ptr);
}
Note that the string "hello" in this example is read-only because it is a string literal. I added const in a few places so you are reminded of this and the compiler will warn you if you try to write to the string. The pointer str_ptr can be modified, but not the string itself.
i ma new c and i am trying sprintf along with pointers. all i get in console is return buf; as is please help me with this code.
#include <stdio.h>
char* stringa(char* str);
int main()
{
char* ss = "123";
stringa(ss);
return 0;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
i tried many other ways too like sprintf_c and my computer shut down for serious. i am learning c.
Maybe this is what you want
#include <stdio.h>
char* stringa(char* dest, char* src)
int main()
{
char buf [100] ;
char* ss = "123";
printf("%s\n", stringa(buf, ss));
return 0;
}
char* stringa(char* dest, char* src)
{
sprintf(dest,"hello %s", src);
return dest;
}
In function 'char* stringa(char* str)' you are not allocating space in the heep for the char array 'buf' you are allocating space on the stack for that variable. (meaning after the function finishes, the variable 'buf' will be wiped away because it will be out of scope) therefore you must ask the compiler to allocate space in memory for this array, I recommend using malloc()
ex:
char* stringa( char* str)
{
char *buf = (char*)malloc(sizeof(char) * 100);
sprintf(buf,"hello %s", str);
return buf;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
The problem with this code is that the buf char array is local to the stringa function. When the function returns, the memory occupied by the buf array is not valid anymore (for example, it could be reused later to store the content of other variables, arrays, etc.).
So when the function returns, you are giving the caller a pointer to garbage memory, to invalid data. The C compiler is trying to help you with that warning message; it's telling you: "Sorry, you are trying to pass back to the caller the address of a local variable (i.e. the buf char array) that is not valid anymore when the function terminates."
To fix this problem one option could be to allocate the char array for the output string at the call site, and let the invoked stringa function write into the caller-provided array:
#include <stdio.h>
char* stringa(char* dest, const char* str);
int main()
{
const char* ss = "123";
char buf[100];
stringa(buf, ss);
return 0;
}
/* Write the final message into 'dest'.
* Return the same dest address.
*/
char* stringa(char* dest, const char* str)
{
/* Note: better using a safe string function
* to prevent buffer overflows (e.g. sprintf_s),
* passing the maximum destination array size as well.
*/
sprintf(dest,"hello %s", str);
return dest;
}
Note that I also added some consts in your code to enforce some const-correctness for read-only input strings.
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.
I have the following program:
#include <stdio.h>
#define MAXLEN 100
char *my_strcat(char *strp1,char *strp2) {
char str[MAXLEN], *strp;
strp = str;
while (*strp1 != '\0') {
*strp++ = *strp1++;
}
while (*strp2 != '\0') {
*strp++ = *strp2++;
}
*strp = '\0';
strp = str;
return strp;
}
void test_strcat(void) {
char *strp1, *strp2, *strp3, str1[MAXLEN], str2[MAXLEN];
printf("Testing strcat! Give two strings:\n");
gets_s(str1, sizeof(str1));
gets_s(str2, sizeof(str2));
strp1 = str1;
strp2 = str2;
strp3 = my_strcat(strp1, strp2);
printf("Concatenated string: %s", strp3);
}
int main(void) {
test_strcat();
}
The function char *mystrcat is supposed to concatenate two strings, and I test it with
test_strcat. The program runs without errors but instead of printing the concatenated string a smiley symbol is printed. I have gone through the program with debugging and it
appears that the result sent back by my_strcat is the correct string. However, when
going into the last line where strp3 is supposed to be printed it appears red in the
debugging tool, implying that its value is about to change. After the printf call, strp3
no longer points to the concatenated string. Anyone knows what could be causing this error?
Here is the problem:
char str[MAXLEN], *strp;
strp = str; // str is a local variable
...
return strp; // <<== WRONG!!!
Since str is a local variable that disappears as soon as you return, the value pointed to by strp becomes invalid the instance the caller gets the control back.
Use malloc instead of allocating memory in the automatic storage area (i.e. on the stack) will fix this problem:
char *str = malloc(strlen(strp1)+strlen(strp2)+1);
char *strp = str;
I suggest you 2 ways as following.
first,
char *my_strcat(char *strp1,char *strp2) {
static char str[MAXLEN * 2]; /* from char str[MAXLEN] */
second,
char *my_strcat(char *strp1,char *strp2) {
char *str = malloc(strlen(strp1) + strlen(strp2) + 1);
because in my_strcat function, you allocated the str as auto variable.
When my_strcat function is finish, str will be freed.