Confused about char arrays - c++

I am trying to implement the functions below, but printing out the output of Printme(), the program that freezes . Any ideas why?
int main()
{
for (int i=0; i<12; i++)
{
cout<< PrintMe()[i];
}
return 0;
}
char * PrintMe() {
char str[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}

Your code invokes Undefined Behaviour as you are returning a pointer to a temporary.
As soon PrintMe ends its execution, str becomes destroyed. Thus the pointer your accessing with PrintMe()[i] is invalid.
To fix this you have to return a heap allocated string (no automatic storage duration). But dont forget to destroy it afterwards:
char * PrintMe() {
char* str = new char[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}
char* str = PrintMe();
for (int i=0; i<12; i++)
{
cout<< str[i];
}
delete[] str;
Or as you're writing c++ nontheless, why dont you go with a std::string?

In your PrintMe function, you are returning a pointer to a local variable. This is undefined behavior:
char* PrintMe() {
char str[12];
//...
return str; // cannot do this, UB.
}
This works if you change the return type to std::string
std::string PrintMe() {
char str[12];
//...
return str;
}
The reason why the above now works is that a std::string is being constructed from the local array and returned instead of the local variable.

The program has undefined behaviour because function PrintMe returns a pointer to the first element of a local array that will be destroyed after exiting the function. So the pointer will not be valid.
Change the function the following way that to get the predicted result
char * PrintMe() {
static char str[12];
strncpy (str, "hello world", 11);
str[11] = 0;
return str;
}

Related

How to convert my string into array of chars

Here is a problem. When I try to convert it by using strncpy_s, array has some type of "trash data" from memory in the end of it. Even when I fill buffer with "\0". How to convert it clear?
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
strncpy_s(text, strin.c_str(), sizeof(text) - 1);
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
The idea to use c_str() function to convert the std::string to a a-string. Then we can simply call strcpy() function to copu the c-string into char array
std::string s = "Hello World!";
char cstr[s.size() + 1];
strcpy(cstr, s.c_str()); // or pass &s[0]
std::cout << cstr << '\n';
return 0;
When using the strncpy_s function you tell it to copy as many chars as will fit into your buffer "text". Since the string you create the "example" instance with is shorter, the copy function will keep going after the end of the actual string.
That is where your garbage comes from. Even worse you risk a Segmentation Fault this way. Your code might access parts of the RAM it is not allowed to read from. That will cause it to crash.
You are right though to copy the data pointed to by the return of c_str(). The pointer returned by c_str() points to data that belongs to the std::string object and might be changed or even invalidated by that object. (Read more here)
Here's a modified version of your code that should avoid the garbage:
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
if(strin.length()+1 <= sizeof(text)) {
strncpy_s(text, strin.c_str(), strin.length()+1);
} else {
//some error handling needed since our buffer is too small
}
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}

How do I transfer const char* from function to function?

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?
The problem
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.
The solution
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.
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;
}
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.
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".

visual c++ VC6 static

The following C++ function has not been working in Visual Studio 6 (1998 year) until I added static. Why?
char* test(char* s1)
{
static char s[100]; strcpy(s, s1); char* r = s1;
if(s[0] == '\n')
{
s[0] = ' ';
cout << "\n";
}
return r;
}
It's dangerously unsafe (undefined behavior) to return a pointer to a stack variable. That includes arrays allocated on the stack. The memory occupied by a stack variable is essentially deallocated as soon as the function returns.
char* test(char* s1)
{
char s[100];
...
return s; // Bad! s is invalid memory when the function returns
}
By making the array allocation static, it's allocation will persist and is safer...
char* test(char* s1)
{
static char s[100];
...
return s;
}
But if any code path caches the pointer returned from "test", another code path that calls this function could invalidate the previous result.
For your example, you probably want to duplicate the string before returning. With the expectation that the caller will "free" the memory later:
char* test(char* s1)
{
char* s = strdup(s1);
strcpy(s, s1);
if(s[0] == '\n')
{
s[0] = ' ';
cout << "\n";
}
return s; // caller is expected to "free" the memory allocation later
}

How to modify array that pointer points to

I need to pass a char pointer to function, then change the value that it points to inside the function and print values outside the function.
The problem I have is that I'm losing it when I leave function and try to print it outside. What can I do to avoid this?
This is an code example:
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
cout << (pText);
cout should print
moob adaB
When I print inside the function, everything is fine(it prints reversed).
My task is to print It out outside the function (as you can see in a 4th line of code)
This is the full of code which have the bug (printing inside func works, outside didn't work)
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
char reverseText(char *text);
int main(){
char array[] = "Bada boom";
char *pTekst = array;
reverseText(pTekst);
cout << (pTekst); //in here it doesn't work
}
char reverseText(char *text){
char befRev[100]; int lenght=-1;
/*until *text doesn't meet '\0' */
for(int i=0;*text!='\0';i++){
befRev[i]=(*text);
text++;
lenght++;
}
/*reversing*/
int j=0;
for(int i=lenght;i>=0;i--){
*(text+j)=befRev[i];
j++;
}
for(int i=0;i<=lenght;i++) //in here it does print the right value
cout << text[i];
};
Just re-arrange the array in-place. The pointer itself doesn't need to change:
#include <cstring>
#include <algorithm>
void reverseText(char* array)
{
auto len = std::strlen(array);
std::reverse(array, array+len);
}
int main()
{
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText << std::endl;
}
Output:
moob adaB
If you really wanted to provide a pointer that points to a different address to the caller, you could simply return it:
char* foo(char* stuff)
{
char* tmp = ....;
...
// do some stuff
...
return tmp;
}
Alternatively, you could pass the pointer by reference, but the intent is less clear than in the previous version:
void foo(char*& stuff)
{
stuff = something_else;
}
But in both cases, you must make absolutely sure the thing the new pointer points to is valid outside of the function. This might require some dynamic memory allocation. For your case, it seems the best and simplest option is to re-arrange the array in place.
To answer your question, you have an error in logic. Notice that in your first loop in reverseText you increment the local pointer text. In your second loop you did not reset text to it's original value so beforeRev is being copied over starting at location text+offset.
If you were to look at pText on return from call to reverseText you would find it contains:
"Bada boom\0moob adaB"
Your reverseText should be renamed palindrome :)
This is pretty straightforward. Some points to note:
An array decays to a pointer when you pass it to a function.
You are passing in a null terminated string. So the length of the char array you are passing in is the length of the string (including white space) +1.
Because you are using a pointer there is no need to assign a temp variable to hold everything.
Here is some code in C that is easy to translate to C++. Working out the actual reverse algorithm is left for you as an exercise.
#include<stdio.h>
void reverseText(char* text)
{
// Hint: It can be done in one loop!
int i;
for(i = 0; i < 9; i++)
{
// Your algorithm to reverse the text. I'm not doing it for you! ;)
*(text + i) = 'r';
}
}
int main()
{
char array[] = "Bada boom";
reverseText(array);
printf("The text reversed: %s\n", array);
return 0;
}
My final code:
#include <iostream>
void reverseText(char* text){
int length=-1; char tmp;
/*Length = sign from 0 to 8 without counting explicit NUL terminator*/
for(int i=0;*(text+i)!='\0';i++){
length++;
}
int j=0; int i=length;
while(j<i){
tmp=*(text+j); //tmp=first
*(text+j)=*(text+i); //first=last
*(text+i)=tmp; //last=tmp
j++;
i--;
}
}
int main(){
char array[] = "Bada boom";
char *pText = array;
reverseText(pText);
std::cout << pText;
}
I should have read more about pointers before I started this exercise.
You can either return a pointer or pass a pointer to pointer as a function argument.
//pointer to pointer
void reverseText(char** textPtr) {
char* newText = ...; //initialize;
...
*textPtr = newText; //assign newText
}
//return pointer
char* reverseText(char* text) {
char* newText = ...; //initialize
return newText;
}
Remember that if you allocate memory in this function you must do it dynamically (with new or malloc) and you have to free it afterwards (with delete or free respectively). Memory allocation in a function like this is probably a bad practice and should be avoided.

C++ char sequence function always return empty string

Just start learning C++ and trying to make a simple function that do substring with following code:
char* substring(int start, int end, const char* target)
{
size_t length = strlen(target);
char result[(length + 1)];
int iterator = 0;
for(int i = start; i < length; i++)
{
if(i <= end)
{
result[iterator] = target[i];
iterator++;
}
}
result[iterator] = '\0';
cout << result << endl; // This give correct result "aya";
return result;
}
When I use these function on main method:
int main(int argc, char** argv) {
char some_text[] = "Saya Makan";
char* sub = substring(1, 3, some_text); // No string returned
cout << "Substring Result is: " << sub;
return 0;
}
It give output is like this:
aya
Substring Result is:
RUN SUCCESSFUL (total time: 44ms)
As seen on the result, my function isn't returning anything but empty string although a line of code before return, the "result" variable echoed result correctly. Would you please explain to me what is happening inside my function, am I missing something?
You are returning pointer to a local array which is not required to live beyond the function.
You need to make the buffer persist beyond the scope of the function by allocating it dynamically using malloc. And ofcourse remember to free it later.
Oh just noticed its C++.
So drop the idea of malloc and free simply use std::string and not char *.