C: printf("%s\n", str) produces gibberish? [duplicate] - c

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 3 years ago.
I have some C code that is supposed to call a function and return a string. Somewhere I read this is difficult due to memory allocation not being constant or something? Anyway, I was told I should rather return the pointer to the string. However, I can't explain why printf sometimes produces gibberish, and sometimes not:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * execTasks() {
int d, m, y;
char str[6] = {};
d = 10; m = 5; y = 18;
memset(&str, 0, sizeof(str));
sprintf(str, "%02d%02d%02d", d, m, y);
printf("Works fine: %s\n", str); // Works fine even with additions
char *s_ptr = str;
return s_ptr;
}
int main() {
char * str;
str = execTasks();
printf("%s", str); // works fine!
printf("%s\n", str); // produces gibberish!
printf("%s,%s", str, str); // also gibberish!
return 0;
}
Can somebody explain to me why printf("%s", str); works fine, while printf("%s\n", str); and variations print out gibberish?
Or am I doing something wrong with returning the pointer? Essentially the function should return a date as string in the format DDMMYY. I need this string later in the main function to append it to another string.

The array char str[6] is local to the execTasks function. After execTasks returns, that memory is reclaimed and can be used by other code. It happens that the last two printfs in main use that memory and corrupt the string, whereas the first printf in main doesn't. However, this code is still invalid (as in Undefined Behavior) as it can also produce gibberish or crash in the right circumstances (e.g. a different compiler, architecture, or standard library implementation).
To fix that you shall not return pointers to local variables, and instead either use a dynamically allocated copy of the string:
char * execTasks() {
int d, m, y;
char str[7] = {};
// ...
return strdup(str); // mallocs a copy of str
}
int main() {
char * str = execTasks();
printf("%s,%s", str, str);
free(str); // reclaim memory
}
Or use a variable that is local to main:
int execTasks(char *str, size_t size) {
int d, m, y;
d = 10; m = 5; y = 18;
return snprintf(str, size, "%02d%02d%02d", d, m, y);
}
int main() {
char str[7];
execTasks(str, sizeof(str));
printf("%s,%s", str, str);
}
Here execTasks returns the amount of characters (not including the null terminator) that would be needed to hold the result. It can be used to detect when the provided buffer is too small, though I don't do that in this simple example (if it's too small the string will simply be truncated).
Notice also that the amount of the memory required for the string is seven chars, because you need an extra byte for the null terminator.

Related

Confused between passing strings to a function (C)

Why this works:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char st[] = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
And this doesn't:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char*st = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
In first I initialized my string using:
char st[]="Hello"; (using array)
And in latter I used:
char*st="Hello"; (using pointer)
I'm kind of getting confused between these 2 initialization types, what's the key difference between declaring a string by using char st[]="Hello"; and by using char*st = "Hello";.
With char st[] = "Hello";, st[] is a modifiable array of characters. The call slice(st, 1, 6); takes the array st and converts to a pointer to the first element of the array. slice() then receives that pointer, a pointer to modifiable characters.
With char *st = "Hello";, st is a pointer that points to a string literal "Hello". With the call slice(st, 1, 6);, the function receives a copy of the pointer - a pointer to the string literal. Inside slice(), code st[i] = ... is attempting to modify a string literal, that is undefined behavior (UB). It might work, it might fail, it might work today and fail tomorrow - it is not defined.
Do not attempt to modify a string literal.
... passing strings to a function ...
In both cases, code does not pass a string to slice(), but a pointer to a string. Knowing that subtle distinction helps in understanding what is truly happening.
This is an artifact of old syntax in C:
char * s = "Hello world!";
is a non-const character pointer to const memory. It is still permitted by syntax, but the string is still not a mutable object. To be pedantic it should really be written as:
const char * s = "Hello world!";
In contrast:
char s[] = "Hello world!";
allocates a local (on the stack), mutable array and copies the string data to it (from wherever the non-mutable copy is stored in memory). Your function can then do as it likes to your local copy of the string.
The type char [] is different from the type char* (char* is a variable - int. but char[] is an array which is not a variable). However, an array name can be used as a pointer to the array.
So we can say that st[] is technically similar to *str .
the problem in the 2nd version of your code
If you have read-only strings then you can use const char* st = "hello"; or simply char* st = "hello"; . So the string is most probably be stored in a read-only memory location and you'll not be able to modify it.
However, if you want to be able to modify it, use the malloc function:
char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);
**So to allocate memory for st, count the characters ("hello"-strlen(st)=5) and add 1 for this terminating null character , and functions like scanf and strcpy will add the null character;
so the code becomes :
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char *st =malloc(6*sizeof(char)) ;
const char *cpy="hello";
strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
you can fill your string also by a for loop or by scanf() .
in the case of a large allocation you must end your code with free(st);

String returned from function contains garbage [duplicate]

This question already has answers here:
Returning an array using C
(8 answers)
Closed 3 years ago.
I want the function lch() to return a string that can be used outside the function.
This is the code I have written, but it does not seem to work:
char *lch(char *ch,int n){
char c[n];
for(int i=0;i<n;i++){
c[i] = *ch;
}
puts(c); // check output string inside function
return c;
}
char str[100],*p;
main(){
p = lch("a",20);
puts(p); // check output outside function
}
I am confused with strings and how they should be passed to functions.
I want the output string to become the same on both calls to puts().
What should I do?
That is the result of the code above:
aaaaaaaaaaaaaaaaaaaa // inside the function
        ¢ÞêÊ· // outside the function
First of all, returning locally allocated storage will not work. You have to return dynamically allocated storage, and with a proper size to accommodate the null-terminator:
char *c = malloc(n+1);
/* ... */
/* end of program: */
free(p);
Second, you want to pass a character to your function, not a string:
char *lch(char ch,int n){
/* ... */
c[i] = ch;
/* ... */
p = lch('a', 20);
Third, you have to null-terminate your string:
int i;
for(i=0;i<n;i++){
c[i] = ch;
}
ch[i] = '\0';
puts(c); //check output string inside function
Here's the dynamically-allocated storage approach:
#include <stdlib.h>
#include <stdio.h>
char *lch(char ch,int n){
char *c = malloc(n+1);
int i;
for(i=0;i<n;i++){
c[i] = ch;
}
c[i] = '\0';
puts(c); //check output string inside function
return c;
}
char *p;
int main(void){
p = lch('a',20);
puts(p); //check output outside function
free(p);
return 0;
}
This also fixes the declaration and return type of main (main is supposed to be int main(void) or int main(int argc, char **argv)), removes the unneeded variable str, and adds needed #includes.
The reason your code does not do what you expect it to do is because the string in the function is allocated on the stack, which means that its memory is cleaned as soon as you exit the function.
That means the pointer p points to garbage value after the call to lch().
Also, you can not declare an array of size that is not a constant value, so the line:
char c[n];
would simply not work.
To solve this, you will need to dynamically allocate the string using malloc(3) :
char* lch(char ch, int n)
{
char * c;
/* Allocate n bytes of memory for the string */
c = malloc(n + 1);
if (NULL == c)
{
/* Failed to allocate memory, exit the function */
return c;
}
for(int i = 0; i < n; i++)
{
c[i] = ch;
}
/* Add a terminating null byte (to make it a string) */
c[i] = '\0';
puts(c);
return c;
}
int main(void)
{
char * p;
p = lch('a', 20);
puts(p);
/* Free the string from the memory */
free(p);
return 0;
}
I added a few fixes to the code but the main thing you need to look at is the use of malloc(3).
I dynamically allocated n+1 bytes of memory for the string, then wrote the data into the string (plus a '\0'), and when the function exits the memory will still be available and wont be corrupted.
The call to free is needed to free the memory we have allocated.
You can read more about malloc(3) here: https://linux.die.net/man/3/malloc

fprint cannot print concatenated string referenced by pointer returned from function

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.

I wrote a substr function in c, but can not get the returned value in main function

I wrote a substr function in c, I can get the returned value inside the substr function, but can not get the returned value in main function. Below is all the code:
#include <stdio.h>
#include <string.h>
char* substr(char *source, int start, int length)
{
char result[10];
char *r = result;
strncpy(result, source+start, length);
printf("substr: %s\n", r);
return r;
}
int main()
{
printf("main: %s\n", substr("HELLO", 1, 2));
}
and the output is:
substr: EL
main:
I'm not familiar with c, anybody get the idea to fix this, thanks in advance.
result only exists during the call to your substr.
Your main is referencing bad memory.
you could fix it by:
making result static in substr.
dynamically allocating result (remember to free)
making result global
As cthulhu ( "Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn" ) points out: even if you applied one of my fixes: your string isn't nul terminated.
Also since you have a fixed size result buffer, you could cause problems by asking for a substring longer than 10 - either check your arguments, or don't use a fixed size buffer.
I haven't tested this, so there may well be an "off by one" problem or two lurking in the corners...
/*
* Caller must free the results if they are non null
*/
char* substr(char *source, int start, int length)
{
/* If the input is NULL, return NULL */
if (source == NULL) return NULL;
int len = strlen(source);
/* If the requested start is off the end of the string, return NULL */
if (start > len) return NULL;
/* If the requested length is 0 or less, return NULL */
if (length <= 0) return 0;
char *r = (char*)malloc(length + 1); /* allow space for null terminator */
if (r != NULL) {
int i = 0;
while(source[start] != '\0' && i < length) {
r[i++] = source[start++];
}
r[i] = '\0';
printf("substr: %s\n", r);
}
return r;
}
If you're going to be expecting to return a value to the caller then you should pass the place where the string will be stored to the function. Standard library functions like strcpy do this. Here is a very simple example. It assumes dest is already declared and is big enough to store it.
char * substr(char * dest, char * src, int start, int length)
{
// Move substring into passed destination pointer
strncpy(dest, src + start, length);
// Append null to the end to terminate string
dest[length] = 0;
// Return string pointer that can be used in printf and other places
return dest;
}
int main(int argc, char const *argv[])
{
char * test = "This is a test.";
char * dest = malloc(10);
printf("%s", substr(dest, test, 5, 2));
free(dest);
return 0;
}
Output:
is
Edit: To all the people returning values that are malloc'd inside the function, how do you expect people to free the memory if they just use it in a print statement? They receive no pointer to free and the memory will just be left hanging there.
The below code allocate memory on the heap. Just free your memory when you are done. strlcpy always NUL-terminate its strings as others have pointed out.
#include <string.h>
char *
substr(char *s, int start, int len)
{
char *ss;
if(strlen(s) < start + len)
return NULL;
if((ss = malloc(len + 1)) == NULL)
return NULL;
strlcpy(ss, s + start, len);
return ss;
}
int
main(void)
{
char *s = substr("Hello World!", 6, 5);
printf("%s\n", s);
free(s);
return 0;
}
Should print World.
To use strlcpy in Debian Linux use:
gcc -lcext -o prog prog.c
If your operating system doesn't provide strlcpy just include it yourself in your source. It is licensed under the BSD license, that means free to use, sell, etc, as long you include the license itself.
The implementation of strlcpy can be found on OpenBSD's CVS Web.
Dynamic and Static Variables in C
Variable declarations can be outside all functions or inside a function
Declarations outside all functions are global and in fixed memory locations
The static declaration declares a variable outside a function to be a “file global” (cannot be referenced by code in other source files)
Declarations within a block statement {} (function body or block statement nested within a function body):
Are dynamically allocated, unless declared static
Are allocated memory when program execution enters the block
Memory is released when execution exits the block
If a function calls itself (directly or indirectly), it gets a new set of dynamic variables (called a stack frame)
This is handled no differently from any other call to the function
You have problem, the variable result[] is a variable that has been allocated in side the function — whose lifetime extends across the entire run of the function(allocated at the stack!) because of that you need to make the result Dynamic variable
Fix code:
#include <stdio.h>
#include <string.h>
char* substr(char *source, int start, int length)
{
char* result;
char *r;
result=(char*)malloc(sizeof(char)*10);
r = result;
strncpy(result, source+start, length);
printf("substr: %s\n", r);
return r;
}
int main()
{
char* r=substr("HELLO", 1, 2);
printf("main: %s\n",r );
free(r)//Don't forget to free it!
}
OR you can make result[] global variable like this:
#include <stdio.h>
#include <string.h>
char result[10];//<======Global
char* substr(char *source, int start, int length)
{
char *r=result;
r = result;
strncpy(result, source+start, length);
printf("substr: %s\n", r);
return r;
}
int main()
{
printf("main: %s\n",substr("HELLO", 1, 2));
}

C : reverse a string in place. I used the prog answered in an earlier question. It compiles ok but crashes with segmenation fault

I call the function provided by Chris Conway (How do you reverse a string in place in C or C++?) from main (C code). When I run this program using cygwin, program crashes when it is in while loop (commented the lines where it breaks). Could you please explain what is going wrong here. Thanks
#include <stdio.h>
#include <string.h>
void strrev(char* z);
int main()
{
char *a;
printf("before reverse: %s\n", a);
strrev(a); // function provided by Chris Conway
printf("after reverse: %s\n", a);
return 0;
}
void strrev(char *str) {
char temp, *end_ptr;
/* If str is NULL or empty, do nothing */
if( str == NULL || !(*str) )
return;
end_ptr = str + strlen(str) - 1;
/* Swap the chars */
while( end_ptr > str ) {
temp = *str;
*str = *end_ptr; //crashes here (cygwin gives segmentation fault)
*end_ptr = temp; //for testing, if I comment out line above, it crashes here
str++;
end_ptr--;
}
}
The function is fine, but your main() does not appear to initialize the string a.
Try:
int main() {
char a[1024];
strcpy(a, "Some string");
printf("before reverse: %s\n", a);
strrev(a); // function provided by Chris Conway
printf("after reverse: %s\n", a);
return 0;
}
Note that I create a copy of "Some string" inside a (instead of directly assigning char* a = "Some String") because trying to alter a constant string directly will not compile. And if you did manage to compile (e.g. lax compiler, or you forced the constness away via cast/const_cast) then you run a very high risk of crashing your program, because "Some string" is actually in a portion of memory that is read-only on some systems, which is why a copy must be made inside a local variable (i.e. on the stack) or a new variable (allocated with new or malloc, i.e. on the heap.)

Resources