Reputation: 113
Here is an example of what I am trying to do:
#include <stdio.h>
FILE* f;
const char* getstring()
{
f = fopen ("hello.txt", "r");
char x[200];
for (int i = 0; i < 200; i++) x[i] = 0;
for (int c = getc(f), i = 0; (c != EOF) && (i < 200); c = getc(f), i++)
x[i] = c;
fclose(f);
printf ("getstring(): x = %s", x);
const char* y = x;
printf ("getstring(): y = %s", y);
return y;
}
void printstring (const char* string)
{
printf ("%s", string);
}
int main()
{
printstring(getstring());
printf ("\nprintf: %s", getstring());
return 0;
}
and the output is:
getstring(): x = Hello World
getstring(): y = Hello World
���getstring(): x = Hello World
getstring(): y = Hello World
printf: ��������
I don't know why the printstring()
function is outputting nothing and printf
is outputting random data or why there is a bit of random data at the end of the string
when I use the printstring()
function.
Is there any way to fix this and what am I doing wrong?
Upvotes: 4
Views: 821
Reputation: 113
This is the answer for C code (not C++). In the code in NPE's answer on the similar question that I found at this link, which I didn't find before I posted this question, I found the malloc(bytes)
function does the trick but if you compile with gcc
, you have to have to convert the malloc function as a char* manually by using (char*) malloc (bytes)
. I also found that because it's using pointers you will have to treat the allocated string as a global variable when you free()
it.
Here is an example of the working code based on the code in my question:
#include <stdio.h>
#include <stdlib.h>
FILE* f;
char* getstring()
{
f = fopen ("hello.txt", "r");
char* x = (char*) malloc (200);
int length = 0;
for (int i = 0; i < 200; i++) x[i] = 0;
for (int c = getc(f), i = 0; (c != EOF) && (i < 200); c = getc(f), i++)
{ x[i] = c; length++; }
fclose(f);
return x;
}
void printstring (char* string)
{
printf ("%s", string);
free (string);
}
int main()
{
printstring(getstring());
return 0;
}
And this outputs the exact first 200 bytes of "hello.txt".
Upvotes: 0
Reputation: 722
Since others have explained how to go about resolving the issue, I'll expand the other answers a bit and explain why you had an issue in the first place.
To put it simply, whenever a function is called, it is given a stack frame (also called activation record) of its own. That is to say: it is given an area of memory where it can place its local variables. When the function returns, the stack frame is destroyed. If you then call another function, the stack frame of that function overwrites the stack frame of the previous function.
In this specific case, when getstring
returns and printstring
and subsequently printf
are called, the stack frames of the latter two along with that of main
overwrite the data that was previously located within the stack frame of getstring
. The most likely result is that printf
will output complete junk. In the worst case, it can make the entire program crash if the null terminator of the string was overwritten.
It is also interesting to note that in your case it seems that a binary value corresponding with that of the null terminator \0
was inserted somewhere, because only a bit of junk is printed before printf
returns. This would indicate that it did not stop at the original null terminator of the character array x
but rather encountered a value it interpreted as the null terminator and returned.
If you wish, you can read more about the call stack on Wikipedia.
Upvotes: 0
Reputation: 16454
The C string is stored in a function local char array. This array is destroyed when the function is left. Since the question is tagged as C++ use std::string
#include <iostream>
#include <string>
#include <fstream>
std::string getstring()
{
std::ifstream f("hello.txt");
std::string x;
x.resize(200);
for (int i = 0; i < 200; i++) x[i] = 0;
for (int c = f.get(), i = 0; (c != EOF) && (i < 200); c = f.get(), i++)
x[i] = c;
std::cout << "getstring(): x = " << x;
const std::string& y = x;
std::cout << "getstring(): y = " << y;
return x;
}
void printstring (const std::string& string)
{
std::cout << string;
}
int main()
{
printstring(getstring());
std::cout << "\nprintf: " << getstring();
return 0;
}
Upvotes: 3
Reputation: 73366
The problem is that getstring()
returns a pointer to a local array. This array gets destructed when the function returns, so you have an dangling pointer. Using this pointer is then undefined behavior. Anything can happen: for example you can get garbage random value, you can get the old unchanged value, or the system could crash.
Since this question is labelled c++, just use std::string
instead of char*
, and this kind of nightmare will vanish for good.
Note that Using std::string
in prinf()
would require you get a pointer with .c_str()
.
If for an obscure reason, you are required to use char*
you'd have to to use strdup()
or llocate some memory for the c string and return a pointner to that memory. But the caller must then delete this pointer if you don't want memory to leak.
Upvotes: 6