I am reading some data from file which are nested into each other (like a file tree) to put it into an array.
Reading is done well, but i am not able to put the array back into main(). The result of AnzGrid is 0, so the for-loop will not start.
Has anyone a hint for me how to do it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void read_include(int,int*,char*);
void read_include(int AnzGrid,int* GridIDs,char* Input){
char Line[81];
char* Token;
FILE * File;
FILE * File1;
File = fopen(Input,"r");
printf("opening %s\n",Input);
if (!File){
printf("%s not found here\n",Input);
return;
}
if (File){
while (fgets(Line,80,File)){
printf("%s",Line);
if (strncmp(Line,"GRID ",8) == 0){
Token=strtok(Line," ");
Token=strtok(NULL," ");
GridIDs[AnzGrid] =atoi(Token);
AnzGrid++;
}
if (strncmp(Line,"INCLUDE ",8) == 0){
Token=strtok(Line,"'");
Token=strtok(NULL,"'");
read_include(AnzGrid,GridIDs,Token);
}
}
fclose(File);
}
printf ("%i\n",AnzGrid);
return;
}
int main( int argc, char* argv[] ) {
char Input[81];
int i;
int AnzGrid;
int GridIDs[100];
strcpy(Input,argv[1]);
read_include(AnzGrid,GridIDs,Input);
printf ("=>%i\n",AnzGrid);
for (i=0;i<AnzGrid;i++){
printf ("GridID: %i\n",GridIDs[i]);
}
It's because when you pass arguments to functions they are passed by value, in other words the values of the arguments you pass are copied in the function. That also means that any changes you make to an argument inside a function are made on the copies, and those changes will be lost once the function returns.
There are basically two ways of solving this in C:
Return values from the function using return
Emulate pass by reference by passing a pointer to the data, and using the dereference operator inside the function.
The second alternative could require some example code:
/* Passing `AnzGrid` as a pointer */
void read_include(int *AnzGrid,int* GridIDs,char* Input){
...
(*AnzGrid)++; /* Using the dereference operator */
...
}
You call the function, not by declaring AnzGrid as a pointer, but by using the address-of operator:
int main(...) {
int AnzGrid = 0; /* Initialize */
...
read_include(&AnzGrid,GridIDs,Input); /* Note use of address-of operator `&` */
...
}
Note: In the snippet of code for the main function, I also fix another bug you have, one leading to undefined behavior: You not initializing the AnzGrid variable. Local variables are not automatically initialized, instead their values are indeterminate (and will be seemingly random). Using an uninitialized local variable without initializing it leads to the mentioned undefined behavior. For example, if AnzGrid have an indeterminate value, what would AnzGrid++ do and what would the result be?
Your read_include function should probably return a malloc-ed pointer to some struct containing the read data.
Of course you should adopt the convention that read_include is returning a heap allocated pointer, and free it later suitably.
BTW, you should compile your code with all warnings and debug info (e.g. with gcc -Wall -g if using GCC) and you should learn how to use the debugger (e.g. gdb)
Related
The user specifies the number of lines in the output in the arguments (as the size of the page in pagination), by pressing the key he gets the next lines. How it works now:
Let's say the user chose to receive 1 row at a time:
first string
first string
second string
first string
second string
third string
struct result {
char part[32768];
int is_end_of_file;
};
struct result readLines(int count) {
int lines_readed = 0;
struct result r;
if (count == 0) {
count = -1;
}
while (count != lines_readed) {
while (1) {
char sym[1];
sym[0] = (char) fgetc(file);
if (feof(file)) {
r.is_end_of_file = 1;
return r;
}
strcat(r.part, sym);
if (*"\n" == sym[0]) {
break;
}
}
lines_readed++;
}
return r;
}
int main(int argc, char *argv[]) {
file = fopen(argv[1], "r");
while (1) {
struct result res = readLines(atoi(argv[2]));
printf("%s", res.part);
if (res.is_end_of_file) {
printf("\nEnd of file!\n");
break;
}
getc(stdin);
}
closeFile();
return 0;
}
I know that when I define a struct in the readLines function, it is already filled with previous data. Forgive me if this is a dumb question, I'm a complete newbie to C.
I'm not sure what is the question here, however I'll do my best to address what I understand. I assume the problem lies somewhere around the "previous data" you mentioned in the title and in the comments to the question.
Let's first set an example program:
#include <stdio.h>
struct result {
char part[10];
};
int main (int argc, char *argv[]) {
struct result r;
printf(r.part);
return 0;
}
The variable r has a block scope, so it has automatic storage duration. Since it has automatic storage duration, and no initializer is provided, it is initialized to an indeterminate value (as mentioned by UnholySheep and n. 1.8e9-where's-my-share m. in the comments to the question). I don't yet get all the C intricacies, but based on this, I guess you cannot rely on what the value of r will be.
Now, in the comments to the question you try to understand how is it possible that you can access some data that was not written by the current invokation of your program. I cannot tell you exactly how is that possible, but I suspect it is rather platform-specific than C-specific. Maybe the following will help you:
What is Indeterminate value?
What happens to memory after free()?
Why memory isn't zero out from malloc?
Going further, in the line
printf(r.part);
first we try to access a member part of r, and then we call printf with the value of this member. Accessing a variable of an indeterminate value results in undefined behavior, according to this. So, in general, you cannot rely also on anything that happens after invoking r.part (it doesn't mean there is no way of knowing what will happen).
There is also another problem with this code. printf's first parameter is interpreted as having the type const char *, according to man 3 printf, but there is provided a variable that has the type struct result. Indeed, there is produced the following warning when the code is compiled with gcc with the option -Wformat-security:
warning: format not a string literal and no format arguments [-Wformat-security]
Unfortunately, I don't know C well enough to tell you what precisely is happening when you do such type mismatch in a function call. But as we know that there already happened undefined behavior in the code, this seems less important.
As a side note, a correct invokation of printf could be in this case:
printf("%p", (void *)r.part);
r.part is a pointer, therefore I use the %p conversion specifier, and cast the value to (void *).
When passing values to my functions, I often consider either returning an allocated buffer from my function, rather than letting the function take a buffer as an argument. I was trying to figure out if there was any significant benefit to passing a buffer to my function (eg:
void f(char **buff) {
/* operations */
strcpy(*buff, value);
}
Versus
char *f() {
char *buff = malloc(BUF_SIZE);
/* operations */
return buff;
}
These are obviously not super advanced examples, but I think the point stands. But yeah, are there any benefits to letting the user pass an allocated buffer, or is it better to return an allocated buffer?
Are there any benefits to using one over the other, or is it just useless?
This is a specific case of the more general question of whether a function should return data to its caller via its return value or via an out parameter. Both approaches work fine, and the pros and cons are mostly stylistic, not technical.
The main technical consideration is that each function has only one return value, but can have any number of out parameters. That can be worked around, but doing so might not be acceptable. For example, if you want to reserve your functions' return values for use as status codes such as many standard library functions produce, then that limits your options for sending back other data.
Some of the stylistic considerations are
using the return value is more aligned with the idiom of a mathematical function;
many people have trouble understanding pointers; and in particular,
non-local modifications effected through pointers sometimes confuse people. On the other hand,
the return value of a function can be used directly in an expression.
With respect to modifications to the question since this answer was initially posted, if the question is about whether to dynamically allocate and populate a new object vs populating an object presented by the caller, then there are these additional considerations:
allocating the object inside the function frees the caller from allocating it themselves, which is a convenience. On the other hand,
allocating the object inside the function prevents the caller from allocating it themselves (maybe automatically or statically), and does not provide for re-initializing an existing object. Also,
returning a pointer to an allocated object can obscure the fact that the caller has an obligation to free it.
Of course, you can have it both ways:
void init_thing(thing *t, char *name) {
t->name = name;
}
thing *create_thing(char *name) {
thing *t = new malloc(sizeof(*t));
if (t) {
init_thing(t);
}
return t;
}
Both options work.
But in general, returning information through the parameters (the second option) is preferable because we usually reserve the return of the function to report an error. And we can return several information trough multiple parameters. Hence, it is easier for the caller to check if the function was OK or not by checking first the returned value. Most of the services from the C library or the Linux system calls work like this.
Concerning your examples, both options work because you are referencing a constant string which is globally allocated at program's loading time. So, in both solutions, you return the address of this string.
But if you do something like the following:
char *func(void) {
char buff[] = "example";
return buff;
}
You actually copy the content of the constant string "example" into the stack area of the function pointed by buff. In the caller the returned address is no longer valid as it refers to a stack location which can be reused by any other function called by the caller.
Let's compile a program using this function:
#include <stdio.h>
char *func(void) {
char buff[] = "example";
return buff;
}
int main(void) {
char *p = func();
printf("%s\n", p);
return 0;
}
If the compilation options of the compiler are smart enough, we get a first red flag with a warning like this:
$ gcc -g bad.c -o bad
bad.c: In function 'func':
bad.c:5:11: warning: function returns address of local variable [-Wreturn-local-addr]
5 | return buff;
| ^~~~
The compiler points out the fact that func() is returning the address of a local space in its stack which is no longer valid when the function returns. This is the compiler option -Wreturn-local-addr which triggers this warning. Let's deactivate this option to remove the warning:
$ gcc -g bad.c -o bad -Wno-return-local-addr
So, now we have a program compiled with 0 warning but this is misleading as the execution fails or may trigger some unpredictible behaviors:
$ ./bad
Segmentation fault (core dumped)
You can't return the address of local memory.
Your first example works because the memory in "example" will not be deallocated. But if you allocated local (aka automatic) memory it automtically be deallocated when the function returns; the returned pointer will be invalid.
char *func() {
char buff[10];
// Copy into local memory
strcpy(buff, "example");
// buff will be deallocated after returning.
// warning: function returns address of local variable
return buff;
}
You either return dynamic memory, using malloc, which the caller must then free.
char *func() {
char *buf = malloc(10);
strcpy(buff, "example");
return buff;
}
int main() {
char *buf = func();
puts(buf);
free(buf);
}
Or you let the caller allocate the memory and pass it in.
void *func(char **buff) {
// Copy a string into local memory
strcpy(buff, "example");
// buff will be deallocated after returning.
// warning: function returns address of local variable
return buff;
}
int main() {
char buf[10];
func(&buf);
puts(buf);
}
The upside is the caller has full control of the memory. They can reused existing memory, and they can use local memory.
The downside is the caller must allocate the correct amount of memory. This might lead to allocating too much memory, and also too little.
An additional downside is the function has no control over the memory which has been passed in. It cannot grow nor shrink nor free the memory.
You can only return one thing from a function.
For example, if you want to convert a string to an integer you could return the integer like atoi does. int atoi( const char *str ).
int num = atoi("42");
But then what happens when the conversion fails? atoi returns 0, but how do you tell the difference between atoi("0") and atoi("purple")?
You can instead pass in an int * for the converted value. int my_atoi( const char *str, int *ret ).
int num;
int err = my_atoi("42", &num);
if(err) {
exit(1);
}
else {
printf("%d\n");
}
How can I check if a pointer to function was initialized?
I can check for NULL, but if not null could be garbage, right?
I have the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct client_struct
{
char *name;
char *email;
void (*print)(struct client_struct *c);
} client;
void print_client(client *c)
{
if (c->print != NULL)
c->print(c);
}
int main()
{
client *c = (client *)malloc(sizeof(client));
c->email = (char *)malloc(50 * sizeof(char));
sprintf(c->email, "email#server.com");
c->name = (char *)malloc(50 * sizeof(char));
sprintf(c->name, "some name");
//Uncommenting line below work as expected, otherwise segmentation fault
//c->print = NULL;
print_client(c);
printf("\nEOF\n");
int xXx = getchar();
return 0;
}
How can I check if this pointer really points to function "void (*f)(client *)"?
Comparing size doesn't work because could garbage in same size, correct?
I would like a way to accomplish that preferably according to C standard.
As described in the comments, it is impossible to determine with 100% certainty whether a pointer is garbage.
To avoid such situation, you can provide a "constructor" function, like this:
struct client_struct* client_allocate()
{
struct client_struct* object = malloc(sizeof *object);
if (object)
{
object->name = NULL;
object->email = NULL;
object->print = NULL;
}
return object;
}
Then write in your documentation that the only valid way to create "clients" is by using your function. If you do this, you should also provide a destroy function, where you call free.
Suppose you add a new pointer to your struct one day. Then you update your client_allocate function, where you set this pointer to NULL, and the new pointer will always be properly initialized. There is no need to update all places in code where your struct is allocated, because now there is only one such place.
Caveats
Checking if a pointer to a function is initialized with an valid function is not an easily solvable problem. Any solution, will not be portable across platforms, and is also dependent on the binary format (statically or dynamically linkable formats) that you end up with. There are ways to do this, with varying success, on different binary formats, however I am not going to go over every permutation. Hopefully this will get you going down that rabbit hole :-) and you can figure out the particular solution that works for you in your circumstances.
In order for some of the solutions to work you have to ensure that the linked binaries have exported symbols (it's possible to do it without, but it's a lot harder and I don't have the time). So when you're linking your program ensure that you have dynamic symbols enabled.
Having said that, here's an approach you can use on systems using dlfcn functions. (See History below)
More Caveats
As #Deduplicator points out in his comment below, there may be situations where 0xdeadbeef may arbitrarily happen to point to a valid function, in which case you may end up with a situation where you end up calling the wrong valid function. There are ways to mitigate that situation at either compile-time or runtime but you'll have to build the solution by hand. For example, C++ does it by mangling in namespace into the symbols. You could require that to happen. (I'll think of an interesting way to do this and post it)
Linux / SysV variants (Mac OSX included)
Use dladdr (SysV) (GNU has a dladdr1 as well) to determine which function does the address you provide fall within:
Example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
int is_valid_function_ptr( void *func) {
Dl_info info;
int rc;
rc = dladdr(func, &info);
if (!rc) {
/* really should do more checking here */
return 0;
}
return 1; /* you can print out function names and stuff here */
}
void print(const char *value) {
fprintf(stdout, "%s", value);
}
void call_the_printer(void (*foo)(), const char *value)
{
if(is_valid_function_ptr(foo)) {
foo(value);
}
else {
fprintf(stderr, "The Beef is Dead!\n");
}
}
int main()
{
void (*funcptr)() = (void (*)()) 0xdeadbeef; /* some dead pointer */
call_the_printer(funcptr, "Hello Dead Beef\n");
funcptr = print; /* actually a function */
call_the_printer(funcptr, "Hello Printer\n");
return 0;
}
NOTE Enable dynamic symbols for this to work
GCC/LLVM etc.
use -rdynamic or -Wl,--export-dynamic during the link process, so compile with:
gcc -o ex1 -rdynamic ex1.c
Windows
Windows does its own thing (as always) and I haven't tested any of these, but the basic concept should work:
Use GetModuleHandle and EnumCurrentProcess together to get loaded symbol information and run through the pointers in a loop to see they match any of the address therein.
The other way would be to use VirtualQuery and then cast mbi.AllocationBase to (HMODULE) and see if you get the path of your own binary back.
In c function pointers are no different than regular pointers and by standard they have one value that says the value should not be used and this is NULL.
The way you should work with pointers is to set them only to valid value or NULL. There is no other way you can be sure there is a OK value. And by definition every value that is not NULL should be considered valid.
Like pointed to in other comments and answers, there is not way to check a variable is initialized. That's why initializing vars to NULL and then checking is considered good practice.
If you really want to validate your function pointer is pointing to the correct place, you could export the function and load your pointer from the ELF symbols (see: http://gcc.gnu.org/wiki/Visibility)
Always check for null parameters first of all.
void print_client(client *c)
{
if ((c != NULL) && (c->print != NULL))
{
c->print(c);
}
}
As for your question, nullify your client struct after it's been malloc'd. This way you can ensure that an unassigned function pointer shall indeed ==NULL.
client* create_client(void)
{
client *c = malloc(sizeof(client));
if (c != NULL)
{
memset(c, 0, sizeof(c))
}
return c;
}
I would like to do something like that :
#include <stdio.h>
char * myfunction(char * in);
void myfunction2(char * in, const char ** content);
int main(){
char * name="aName";
char * result = myfunction(name);
return 0;
}
char * myfunction(char * in) {
const char *test = NULL;
myfunction2(in, &test);
return test; // I would like to return the value of test
}
void myfunction2(char * in, const char ** content) {
char input[1024];
//do some stuff to fill input
*content = input;
}
But I'm not able to do it, some weird char are printed instead sometimes...
Thank you for your reply, I understand it well now, but I'm stuck on another side of my problem. I didn't write precisely my use case, so I edited it to be complete.
The most glaring things wrong in this code are:
Implicit declaration of myfunction as int myfunction();
Incorrect const-ness of your pointers.
No return value provided for main()
Implicit declaration of myfunction as int myfunction();
This is easy enough to solve, and your compiler should be barking loudly at you when this happens. As a legacy feature of C, when a function call is encountered where no formal declaration, either by prototype or definition, is known, the function is assumed to return int and accept a variable number of parameters. Therefore in main() your call is assumed to be to a function that looks like this:
int myfunction();
Later when the real myfunction is encountered, at a minimum your compiler should scream at you with warning about how the declaration doesn't match the expected type (because by this time it thinks it is int myfunction()). Even then, however, the call should still go through, but it is terrible practice to rely on this. Properly prototype your functions before use.
Incorrect data types for all your pointers.
The string literal in your function is not bound to local array space. It is a read-only data buffer sitting in a read-only segment somewhere in your program's data blocks. The correct declaration is this:
const char *test = "mytest";
but that has the ripple effect of requiring changes to the rest of this code, which you'll see in a moment.
No return value provided for main()
Be definitive in your conclusion of main(). Apparently C99 allows you to skip this and implementation is supposed to return 0 for you. Don't give them that joy; seize it yourself.
Addressing all of the above...
#include <stdio.h>
void myfunction(const char** in);
int main()
{
const char *result = NULL;
myfunction(&result);
printf("in main() %p : %s\n", result, result);
return 0;
}
void myfunction(const char** in)
{
const char* test = "mytest";
printf("in myfunction() %p : %s\n", test, test);
*in = test;
}
Output (varies by implementation)
in main() 0x8048580 : mytest
in myfunction() 0x8048580 : mytest
See it live.
It looks good to me. May I suggest giving it a prototype or moving your myfunc() definition before main(). Also assigning a value to result when it is declared. That will give you a better idea of what is going on if the function is not doing what you expect.
For some reason, the other answers just pointed out technical detail that's wrong, but failed to notice what is really wrong: You are returning the address of an array on the stack. But when the function returns, accessing that array becomes undefined behavior. Other code may freely overwrite the memory, leaving the worst possible garbage in it, or, conversely, writing to the memory behind the returned pointer may trash any vitally important variable of some other, entirely unconnected parts of the code.
If you want to return a pointer, you must either return a pointer to a static object, or you must return a pointer to something on the heap. Here is the static case:
char* foo() {
static char staticArray[1024];
return staticArray;
}
Using static here guarantees that the memory reserved for staticArray[] will remain reserved for it throughout the execution of your program. There are, however, three downsides of this:
the array size is fixed at compile time
this is generally not multithreading safe since all threads will use the same globally allocated memory
you generally cannot expect the data behind the returned pointer to remain intact across a function call. Consider this code:
void bar() {
char* temp = foo();
temp[0] = 7;
}
void baz() {
char* temp = foo();
temp[0] = 3;
bar();
//now temp[0] is 7 !
}
This might be desirable in some rare cases, however, in most it's not.
So, if you want to be able to freely use the memory behind the returned pointer, you have to malloc() memory for it (and free() it afterwards, of course). Like this:
char* foo(int size) {
return malloc(size);
}
void baz() {
char* sevenBytes = foo(7);
//Do something with seven bytes
free(sevenBytes);
}
void bar() {
char* threeBytes = foo(3);
threeBytes[0] = 3;
baz();
assert(threeBytes[0] == 3); //baz() worked on it's own memory
free(threeBytes);
}
In the case of string handling, there is a number of handy functions available in the POSIX-2008 standard that do the memory allocation for you, among them strdup() and asprintf(). Here are some usage examples:
int main() {
char* hello = strdup("Hello");
char* greeting;
if(0 > asprintf(&greeting, "%s World!\nMemory for hello was allocated at %llx", hello, (long long)hello)) {
//error handling
}
printf(greeting);
free(hello);
free(greeting);
}
This will print something like:
Hello World!
Memory for hello was allocated at c726de80
I have argument with my friend. He says that I can return a pointer to local data from a function. This is not what I have learned but I can't find a counterargument for him to prove my knowledge.
Here is illustrated case:
char *name() {
char n[10] = "bodacydo!";
return n;
}
And it's used as:
int main() {
char *n = name();
printf("%s\n", n);
}
He says this is perfectly OK because after a program calls name, it returns a pointer to n, and right after that it just prints it. Nothing else happens in the program meanwhile, because it's single threaded and execution is serial.
I can't find a counter-argument. I would never write code like that, but he's stubborn and says this is completely ok. If I was his boss, I would fire him for being a stubborn idiot, but I can't find a counter argument.
Another example:
int *number() {
int n = 5;
return &n;
}
int main() {
int *a = number();
int b = 9;
int c = *a * b;
printf("%d\n", c);
}
I will send him this link after I get some good answers, so he at least learns something.
Your friend is wrong.
name is returning a pointer to the call stack. Once you invoke printf, there's no telling how that stack will be overwritten before the data at the pointer is accessed. It may work on his compiler and machine, but it won't work on all of them.
Your friend claims that after name returns, "nothing happens except printing it". printf is itself another function call, with who knows how much complexity inside it. A great deal is happening before the data is printed.
Also, code is never finished, it will be amended and added to. Code the "does nothing" now will do something once it's changed, and your closely-reasoned trick will fall apart.
Returning a pointer to local data is a recipe for disaster.
you will get a problem, when you call another function between name() and printf(), which itself uses the stack
char *fun(char *what) {
char res[10];
strncpy(res, what, 9);
return res;
}
main() {
char *r1 = fun("bla");
char *r2 = fun("blubber");
printf("'%s' is bla and '%s' is blubber", r1, r2);
}
As soon as the scope of the function ends i.e after the closing brace } of function, memory allocated(on stack) for all the local variables will be left. So, returning pointer to some memory which is no longer valid invokes undefined behavior.
Also you can say that local variable lifetime is ended when the function finished execution.
Also more details you can read HERE.
My counter-arguments would be:
it's never OK to write code with undefined behavior,
how long before somebody else uses that function in different context,
the language provides facilities to do the same thing legally (and possibly more efficiently)
It's undefined behavior and the value could easily be destroyed before it is actually printed. printf(), which is just a normal function, could use some local variables or call other functions before the string is actually printed. Since these actions use the stack they could easily corrupt the value.
If the code happens to print the correct value depends on the implementation of printf() and how function calls work on the compiler/platform you are using (which parameters/addresses/variables are put where on the stack,...). Even if the code happens to "work" on your machine with certain compiler settings it's far from sure that it will work anywhere else or under slightly different border conditions.
You are correct - n lives on the stack and so could go away as soon as the function returns.
Your friend's code might work only because the memory location that n is pointing to has not been corrupted (yet!).
As the others have already pointed out it is not illegal to do this, but a bad idea because the returned data resides on the non-used part of the stack and may get overridden at any time by other function calls.
Here is a counter-example that crashes on my system if compiled with optimizations turned on:
char * name ()
{
char n[] = "Hello World";
return n;
}
void test (char * arg)
{
// msg and arg will reside roughly at the same memory location.
// so changing msg will change arg as well:
char msg[100];
// this will override whatever arg points to.
strcpy (msg, "Logging: ");
// here we access the overridden data. A bad idea!
strcat (msg, arg);
strcat (msg, "\n");
printf (msg);
}
int main ()
{
char * n = name();
test (n);
return 0;
}
gcc : main.c: In function ‘name’:
main.c:4: warning: function returns address of local variable
Wherever it could been done like that (but it's not sexy code :p) :
char *name()
{
static char n[10] = "bodacydo!";
return n;
}
int main()
{
char *n = name();
printf("%s\n", n);
}
Warning it's not thread safe.
You're right, your friend is wrong. Here's a simple counterexample:
char *n = name();
printf("(%d): %s\n", 1, n);
Returning pointer to local variable is aways wrong, even if it appears to work in some rare situation.
A local (automatic) variable can be allocated either from stack or from registers.
If it is allocated from stack, it will be overwritten as soon as next function call (such as printf) is executed or if an interrupt occurs.
If the variable is allocated from a register, it is not even possible to have a pointer pointing to it.
Even if the application is "single threaded", the interrupts may use the stack. In order to be relatively safe, you should disable the interrupts. But it is not possible to disable the NMI (Non Maskable Interrupt), so you can never be safe.
While it is true that you cannot return pointers to local stack variables declared inside a function, you can however allocate memory inside a function using malloc and then return a pointer to that block. Maybe this is what your friend meant?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* getstr(){
char* ret=malloc(sizeof(char)*15);
strcpy(ret,"Hello World");
return ret;
}
int main(){
char* answer=getstr();
printf("%s\n", answer);
free(answer);
return 0;
}
The way I see it you have three main options because this one is dangerous and utilizes undefined behavior:
replace: char n[10] = "bodacydo!"
with: static char n[10] = "bodacydo!"
This will give undesirable results if you use the same function more than once in row while trying to maintain the values contained therein.
replace:
char n[10] = "bodacydo!"
with:
char *n = new char[10];
*n = "bodacydo!"
With will fix the aforementioned problem, but you will then need to delete the heap memory or start incurring memory leaks.
Or finally:
replace: char n[10] = "bodacydo!";
with: shared_ptr<char> n(new char[10]) = "bodacydo!";
Which relieves you from having to delete the heap memory, but you will then have change the return type and the char *n in main to a shared_prt as well in order to hand off the management of the pointer. If you don't hand it off, the scope of the shared_ptr will end and the value stored in the pointer gets set to NULL.
If we take the code segment u gave....
char *name() {
char n[10] = "bodacydo!";
return n;
}
int main() {
char *n = name();
printf("%s\n", n);
}
Its okay to use that local var in printf() in main 'coz here we are using a string literal which again isn't something local to name().
But now lets look at a slightly different code
class SomeClass {
int *i;
public:
SomeClass() {
i = new int();
*i = 23;
}
~SomeClass() {
delete i;
i = NULL;
}
void print() {
printf("%d", *i);
}
};
SomeClass *name() {
SomeClass s;
return &s;
}
int main() {
SomeClass *n = name();
n->print();
}
In this case when the name() function returns SomeClass destructor would be called and the member var i would have be deallocated and set to NULL.
So when we call print() in main even though since the mem pointed by n isn't overwritten (i am assuming that) the print call will crash when it tried to de-reference a NULL pointer.
So in a way ur code segment will most likely not fail but will most likely fail if the objects deconstructor is doing some resource deinitialization and we are using it afterwards.
Hope it helps