tags:

views:

149

answers:

9

I want to write the data "somebytes" that I get from a function called NextUnit() to a file named "output.txt", but the code that I wrote does not work. When I open the file, it does not look like my "somebytes". Here is the code:

#include <stdio.h>
#include <string.h>

char* NextUnit()
{
    char Unit[256];
    strcpy(Unit,"somebytes");
    return &Unit[0];
}

int main()
{
    FILE *ourfile;
    ourfile=fopen("output.txt","wb");
    char* somedata;
    somedata=NextUnit();
    printf("%s\n",somedata);
    fwrite(somedata,1,strlen(somedata),ourfile); 
    fclose(ourfile);
}
+3  A: 

You are returning the local address from a function (aka released stack address). Which is then changed once you call the next function.

Ether just return a global constant

const char* NextUnit() { return "somebytes"; }

or copy it into a new memory structure, which you will then need to also free later...

char* NextUnit() 
{ 
    char* newstr = new char[256]; 
    strcpy(newstr,"somebytes"); 
    return newstr;
}

// some code later
char* tmpstr = NextUnit();

// do writing stuff

// free memory
delete tmpstr;
Simeon Pilgrim
+1  A: 

You've declared Unit[256] on the stack in a subprocedure. But when your NextUnit() returns, the variable that was scoped to it goes out of scope, and you are no longer pointing to valid memory.

Consider allocating the memory with new, and then releasing it in the caller, or having the caller pass down a pointer to preallocated memory.

lavinio
+1  A: 

you are returning the local address of a function. Ether just return

const char* NextUnit() { return "somebytes"; }

so it's constant, or copy it into a new memory stucture, which you will then need to also free later...

I don't have enough mojo to comment on the quoted answer, so I have to put this as a new answer.

His answer is trying to say the right thing, but it came out wrong.

Your code is returning the address of a local variable inside the NextUnit() function. Don't do that. Its bad. Do what he suggested.

Trevor Harrison
oh my god, I am too, thanks...
Simeon Pilgrim
+1  A: 

I would rewrite it like this:

char *NextUnit(char *src)
{
    strcpy(src, "somebytes");
    return src;
}

This way you can decide what to do with the variable outside the function implementation:

char Unit[256];
char *somedata = NextUnit(Unit);
Luca Matteis
but string copy always start at the beginning, are you confusing of strcat?
Simeon Pilgrim
Yes, i totally thought it was strcat :)
Luca Matteis
+1  A: 

If you are using C++, the following is a much better way to go about this:

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char ** argv)
{
    ofstream outFile;

    outFile.open("output.txt");
    outFile << "someBytes";
    outFile.close();

    return 0;
}

And, once you are comfortable with that, the next thing to learn about is RAII.

e.James
true, but it doesn't answer his question of wh the code doesn't do what he expects.
jalf
That is a valid point, but if he is coding in C++, the code he posted is not even on the right track. We can explain in detail what is wrong with it, but in the end he will be no further ahead in learning how to properly write data to files in C++.
e.James
A: 

NextUnit returns the address of Unit, which is an array local to that function. That means that it is allocated on the stack, and "released" when the function returns, making the return value non-valid.

To solve this problem you can:

  • Dynamically allocate a new string each time NextUnit is called. Note that in that case you will have to delete the memory afterwards.
  • Create a global string. That's fine for a small "test" application, but generally use of global variables is discouraged.
  • Have main allocate a string (either dynamically or on the stack), pass it as a parameter to NextUnit, and have NextUnit copy to that string.
Tal Pressman
A: 

You have a few problems here. The main one, I think, is that NextUnit() is allocating the buffer on the stack and you're effectively going out of scope when you try to return the address.

You can fix this in a C-style solution by mallocing space for the buffer and returning the pointer that malloc returns.

I think a first step might be to rewrite the code to something more like the following:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* NextUnit()
{
    char *Unit = (char *)malloc( 256 );
    memset(Unit, 0, sizeof(Unit));
    strcpy(Unit,"somebytes");
    return Unit;
}

int main()
{
    FILE *ourfile;
    ourfile=fopen("output.txt","wb");
    char* somedata;
    somedata=NextUnit();
    printf("%s\n",somedata);
    //fwrite(somedata,1,strlen(somedata),ourfile);
    fprintf(ourfile, somedata); 
    free(somedata);
    fclose(ourfile);
}
mrduclaw
eek, just because he is using C functions in C++ doesn't mean we have to pull out mallac/free, it's C++ just stick to new and delete, for consistency with constructors.
Simeon Pilgrim
Sorry -- what part of his code was C++? His C-header files? His C-string functions? His lack of use of OO-design? I don't see any reason to use switch him to C++ for this C question.
mrduclaw
A: 

"Unit" declared as a local variable inside NextUnit which is actually a "stack" variable meaning that it's lifetime is only as long as NextUnit hasn't returned.

So, while NextUnit hasn't returned yet, copying "somebytes" to it is ok, as is printing it out. As soon as NextUnit returns, Unit is released from the stack and the pointer somedata in main will not be pointing to something valid.

Here is quick fix. I still don't recommend writing programs this way this way, but it's the least changes.

#include <stdio.h>
#include <string.h>

char Unit[256];

char* NextUnit()
{

    strcpy(Unit,"somebytes");
    return &Unit[0];
}

int main()
{
    FILE *ourfile;
    ourfile=fopen("output.txt","wb");
    char* somedata;
    somedata=NextUnit();
    printf("%s\n",somedata);
    fwrite(somedata,1,strlen(somedata),ourfile); 
    fclose(ourfile);
}

That works but it's kindof pointless returning the address of Unit when it's actually Global!

Matt H
A: 
Kirill V. Lyadvinsky