Does dynamic memory get extended automatically in C? - c

I was writing a simple program to see how dynamic memory allocations in C works.
#include <stdio.h>
#include <stdlib.h>
int main() {
char* c = (char* ) malloc(sizeof(char) * 1);
int* a = (int* ) malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
*(a+i) = i;
c = "Hello World";
printf("%c\n", *(c+4));
printf("%d\n", *(a+4));
return 0;
}
The output I get is
o
4
I've allocated enough memory to save a single character and an integer. But then, how is a whole string and an array of integers of length 10 getting saved?
Does the memory automatically get extended? Could someone kindly explain how it works?
Thanks.

In accessing the dynamically allocated array a out of bounds, you invoke undefined behavior. The program may do anything, including "working" the way you expected.
int* a = (int* ) malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
*(a+i) = i;
I will suggest a different syntax, and that you not cast the result of malloc.
int* a = malloc(sizeof(int) * 1);
for (int i = 0; i < 10; i++)
a[i] = i;
As for your string:
char* c = (char* ) malloc(sizeof(char) * 1);
c = "Hello World";
You are allocating one byte of memory and c is pointing to it. You then reassign c to point to a string literal. As a result, you can print c without issue. Since the dynamically allocated memory is no longer pointed to, you cannot free it and a very small memory leak is created.
If you wanted to copy Hello World" into the memory c` pointed to initially, you'd write:
strcpy(c, "Hello World");
But this would access out of bounds for c, and we'd be back in the territory of undefined behavior.
Please note that strings in C require a null terminating character at the end. A single char's memory cannot store a string as it only has room for the null terminator.

The assignment c = "Hello World" just causes c to point to the string literal and the single character allocated has been leaked.
You've written beyond the allocated size of the array a but it's not surprise those addresses are accessible to your program so you don't get a protection/segmentation fault.
Your code then ends before you do anything else with malloc() and free() so you never trip over what memory corruption your for-loop may have introduced.
As comments point out "undefined behaviour" includes your program working as intended.
In my experience overwriting the bounds of dynamically allocated memory often appears to work and then crashes about 3 or more allocations later.
Your program is probably terminating before it trips over the mess you've made of it's memory.
In programming breaking things isn't usually a good way to find out how they work.

Related

How do I modify the contents of a string literal without using brackets in C?

Disclaimer: this is for a homework assigment.
Say I have a string that was declared like this:
char *string1;
For part of my program, I need to set string1 equal to another string, string2. I can't use strcpy or use brackets.
This is my code so far:
int i;
for(i = 0; *(string2 + i) != '\0'; i++){
*(string1 + i) = *(string2 + i);
}
This causes a segmentation fault.
According to https://www.geeksforgeeks.org/storage-for-strings-in-c/ , this is because string1 was declared like this: char *string1 and a workaround to avoid segfaults is to use brackets. I can't use brackets, so is there any workaround that I can do?
EDIT: I am also prohibited from allocating more memory or declaring arrays. I cant use malloc(), falloc() etc.
The issue you are having is that string2 does not have memory allocated to it.
Your code is missing some details, but I'll assume it looks something like this:
#include <stdio.h>
int main()
{
char *originalStr = "Hello NewArsenic";
char *newStr;
// YMMV depending on the compiler for this line. Might print (null) for
// newStr or it might throw an error.
printf("Original: %s\nNew: %s\n", originalStr, newStr);
int i;
for (i = 0; *(originalStr + i) != '\0'; i++)
{
*(newStr + i) = *(originalStr + i);
}
printf("Original: %s\nNew: %s\n", originalStr, newStr);
return 0;
}
TL;DR Your Issue
Your issue here is that you are attempting to store some values into newStr without having the memory to do so.
Solution
Use malloc.
#include <stdio.h>
#include <stdlib.h> // malloc(size_t) is in stdlib.h
#include <string.h> // strlen(const char *) is in string.h
int main()
{
char *originalStr = "Hello NewArsenic";
// Note here that size_t is preferable to int for length.
// Generally you want to be using size_t if you are working with size/length.
// More info at https://stackoverflow.com/questions/19732319/difference-between-size-t-and-unsigned-int
size_t originalLength = strlen(originalStr);
// This is malloc's typical usage, where we are asking from the system to
// give us originalLength + 1 many chars.
// The `char` here is redundant, actually, since sizeof(char) is defined to
// be one by the C spec, but you might find it useful to see the typical
// usage of `malloc`.
// Since malloc returns a void *, we need to cast that to a char *.
char *newStr = (char *)malloc((originalLength + 1) * sizeof(char));
// Your code stays the same.
printf("Original: %s\nNew: %s\n", originalStr, newStr);
size_t i;
for (i = 0; *(originalStr + i) != '\0'; i++)
{
*(newStr + i) = *(originalStr + i);
}
// Don't forget to append a null character like I did before editing!
*(newStr + originalLength) = 0;
printf("Original: %s\nNew: %s\n", originalStr, newStr);
// Because `malloc` gives us memory on the stack, we need to tell the system
// that we want to free it before exiting.
free(newStr);
return 0;
}
The long answer
What is a C String?
In C, a string is merely an array of characters. What this means is that for each character you want to have have, you need to allocate memory.
Memory
In C, there are two types of memory allocation - stack- and heap-based.
Stack Memory
You're probably more familiar with stack-based memory than you think. Whenever you declare a variable, you're defining it on the stack. Arrays declared with bracket notation type array[size_t] are stack-based too. What's specific about stack-based memory allocation is that when you allocate memory, it will only last for as long as the function in which it was declared, as you're probably familiar with. This means that you don't have to worry about your memory sticking around for longer than it should.
Heap Memory
Now heap-based memory allocation is different in the sense that it will persist until it is cleared. This is advantageous in one way:
You can keep values of which you don't know the size at compile time.
But, that comes at a cost:
The heap is slower
You have to manually clear your memory once you're done with it.
For more info, check out this thread.
We typically use the function (void *) malloc(size_t) and its sister (void *) calloc(size_t, size_t) for allocating heap memory. To free the memory that we asked for from the system, use free(void *).
Alternatives
You could've also used newStr = originalStr, but that would not actually copy the string, but only make newStr point to originalStr, which I'm sure you're aware of.
Other remarks
Generally, it's an anti-pattern to do:
char* string = "literal";
This is an anti-pattern because literals cannot be edited and shouldn't be. Do:
char const* string = "literal";
See this thread for more info.
Avoid using int in your loop. Use size_t See this thread.
For part of my program, I need to set string1 equal to another string, string2. I can't use strcpy or use brackets.
Perhaps the solution is just as simple as
string2 = string1
Note that this assignes the string2 pointer to point directly to the same memory as string1. This is sometimes very helpful because you need to maintain the beginning of the string with string1 but also need another pointer to move inside the string with things like string2++.
One way or another, you have to point string2 at an address in memory that you have access to. There are two ways to do this:
Point at memory that you already have access to through another variable either with another pointer variable or with the address-of & operator.
Allocate memory with malloc() or related functions.

Dynamically allocating memory for 2d char array

I am using malloc to dynamically allocate a 2d char array. Unless I set every array index to NULL before free(), I get a segmentation fault when trying to free(). Why do I get a segmentation fault?
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int nrows = 20; int ncolumns = 10;
char ** arr = malloc(nrows * sizeof(char *));
for(int i = 0; i < nrows; i++)
arr[i] = malloc(ncolumns * sizeof(char));
arr[0] = "string1";
arr[1] = "string2";
// does not work without the following code:
// for(int i = 0; i < 20; i++)
// arr[i] = NULL;
for(int i = 0; i < 20; i++)
free(arr[i]);
free(arr);
return 0;
}
When you do this:
arr[0] = "string1";
arr[1] = "string2";
You overwrite the contents of arr[0] and arr[1], which contain the addresses of memory returned from malloc, with the address of two string constants. This causes a memory leak, as that memory is no longer accessible. This is also the reason you crash when you call free because these variables no longer hold the addresses of allocated memory.
What you probably want to do here instead is use strcpy, which will copy the contents of the string literal to the memory you allocated.
strcpy(arr[0], "string1");
strcpy(arr[1], "string2");
Now you can free the memory properly.
Your code is ok, the problem comes from the fact that you are assigning string literals to your array here: arr[0] = "string1";.
You are thus replacing the pointer at arr[0], which is pointing to your allocated memory, with the pointer to a string literal.
Pointers to literals are protected, you cannot free (nor write to them) them because you didn't allocate them.
To solve this problem, use strcpy to copy the value of your literal inside your allocated memory:
strcpy(arr[0], "string1");
strcpy(arr[1], "string2");
= operator does not copy the string it only assigns the pointer. So your malloced memory is not accessible anymore for those array elements and attempt to free it is an Undefined Behavoiur which may lead to the segfault.
You need to copy it using strcpy.
Crashing upon a call to free is a sign of incorrect memory management somewhere else in your code. When you set a pointer to NULL then free it, you are not going to crash, because free(NULL) is guaranteed to be benign by the C Standard ยง 7.22.3.3:
7.22.3.3 The free function
...
If ptr is a null pointer, no action occurs. Otherwise, if
the argument does not match a pointer earlier returned by a memory management
function, or if the space has been deallocated by a call to free or realloc, the
behavior is undefined.
Emphasis mine.
As other answers have noted, you are trying to call free on memory that you didn't explicitly allocate with malloc-family functions (since you overwrote arr[i] pointers with pointers to string literals)
Two things to know:
You have two area in you memory (to make easy t understand) heap and stack
malloc, realloc, calloc allocate ressource from heap. I will say only malloc (but it is the same)
free can only free ressource from heap. Stack is reserver for the compiler (it store function call and other data)
The rule for each ressource you get from malloc you have to free it.
to free simply call the free function (but we can optionally assigne null pointer to be sure it is freed).
char * a = malloc(255);
to free
free(a);/* this is mandatory */
a = NULL;/* we can add this to the first line */
In fact it you take the habit to assign NULL value and one time you access it's value you will have NULL deference error: so you will know where to find error
What you try to do:
alloc a array char ** arr = malloc(nrows * sizeof(char *)); and you free it free(arr);
but you alloc 20 arrays of char arr[i] = malloc(ncolumns * sizeof(char));
you ignore it's value arr[0] = "string1"; (you loose the value returned by malloc so you can't free now arr[0]) we are not in C++. So "string1" is stocked on the stack (so malloc can't free it)
and you call free on it.
what you can do
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int nrows = 20; int ncolumns = 10;
char ** arr = malloc(nrows * sizeof(char *));
for(int i = 0; i < nrows; i++)
arr[i] = malloc(ncolumns * sizeof(char));
free(arr[0]);//know we can loose it value because it is freed
arr[0] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
free(arr[1]);//know we can loose it value because it is freed
arr[1] = NULL;// in fact we assign a value just after so this line is useless but is educationnal purpose
arr[0] = "string1";
arr[1] = "string2";
// does not work without the following code:
// for(int i = 0; i < 20; i++)
// arr[i] = NULL;
for(int i = 2; i < 20; i++)//we start at 2 because the first two value are on the stack
{
free(arr[i]);
arr[i] = NULL;//this is useless because we will free arr just after the loop)
}
free(arr);
arr = NULL;// this is useless because we exit the end of program
return 0;
}

Using Malloc for i endless C -String

I was wondering is it possible to create one endless array which can store endlessly long strings?
So what I exactly mean is, I want to create a function which gets i Strings with n length.I want to input infinite strings in the program which can be infinite characters long!
void endless(int i){
//store user input on char array i times
}
To achieve that I need malloc, which I would normally use like this:
string = malloc(sizeof(char));
But how would that work for lets say 5 or 10 arrays or even a endless stream of arrays? Or is this not possible?
Edit:
I do know memory is not endless, what I mean is if it where infinite how would you try to achieve it? Or maybe just allocate memory until all memory is used?
Edit 2:
So I played around a little and this came out:
void endless (char* array[], int numbersOfArrays){
int j;
//allocate memory
for (j = 0; j < numbersOfArrays; j++){
array[j] = (char *) malloc(1024*1024*1024);
}
//scan strings
for (j = 0; j < numbersOfArrays; j++){
scanf("%s",array[j]);
array[j] = realloc(array[j],strlen(array[j]+1));
}
//print stringd
for (j = 0; j < numbersOfArrays; j++){
printf("%s\n",array[j]);
}
}
However this isn't working maybe I got the realloc part terrible wrong?
The memory is not infinite, thus you cannot.
I mean the physical memory in a computer has its limits.
malloc() will fail and allocate no memory when your program requestes too much memory:
If the function failed to allocate the requested block of memory, a null pointer is returned.
Assuming that memory is infinite, then I would create an SxN 2D array, where S is the number of strings and N the longest length of the strings you got, but obviously there are many ways to do this! ;)
Another way would be to have a simple linked list (I have one in List (C) if you need one), where every node would have a char pointer and that pointer would eventually host a string.
You can define a max length you will assume it will be the max lenght of your strings. Otherwise, you could allocate a huge 1d char array which you hole the new string, use strlen() to find the actual length of the string, and then allocate dynamically an array that would exactly the size that is needed, equal of that length + 1 for the null-string-terminator.
Here is a toy example program that asks the user to enter some strings. Memory is allocated for the strings in the get_string() function, then pointers to the strings are added to an array in the add_string() function, which also allocates memory for array storage. You can add as many strings of arbitrary length as you want, until your computer runs out of memory, at which point you will probably segfault because there are no checks on whether the memory allocations are successful. But that would take an awful lot of typing.
I guess the important point here is that there are two allocation steps: one for the strings and one for the array that stores the pointers to the strings. If you add a string literal to the storage array, you don't need to allocate for it. But if you add a string that is unknown at compile time (like user input), then you have to dynamically allocate memory for it.
Edit:
If anyone tried to run the original code listed below, they might have encountered some bizarre behavior for long strings. Specifically, they could be truncated and terminated with a mystery character. This was a result of the fact that the original code did not handle the input of an empty line properly. I did test it for a very long string, and it seemed to work. I think that I just got "lucky." Also, there was a tiny (1 byte) memory leak. It turned out that I forgot to free the memory pointed to from newstring, which held a single '\0' character upon exit. Thanks, Valgrind!
This all could have been avoided from the start if I had passed a NULL back from the get_string() function instead of an empty string to indicate an empty line of input. Lesson learned? The source code below has been fixed, NULL now indicates an empty line of input, and all is well.
#include <stdio.h>
#include <stdlib.h>
char * get_string(void);
char ** add_string(char *str, char **arr, int num_strings);
int main(void)
{
char *newstring;
char **string_storage;
int i, num = 0;
string_storage = NULL;
puts("Enter some strings (empty line to quit):");
while ((newstring = get_string()) != NULL) {
string_storage = add_string(newstring, string_storage, num);
++num;
}
puts("You entered:");
for (i = 0; i < num; i++)
puts(string_storage[i]);
/* Free allocated memory */
for (i = 0; i < num; i++)
free(string_storage[i]);
free(string_storage);
return 0;
}
char * get_string(void)
{
char ch;
int num = 0;
char *newstring;
newstring = NULL;
while ((ch = getchar()) != '\n') {
++num;
newstring = realloc(newstring, (num + 1) * sizeof(char));
newstring[num - 1] = ch;
}
if (num > 0)
newstring[num] = '\0';
return newstring;
}
char ** add_string(char *str, char **arr, int num_strings)
{
++num_strings;
arr = realloc(arr, num_strings * (sizeof(char *)));
arr[num_strings - 1] = str;
return arr;
}
I was wondering is it possible to create one endless array which can store endlessly long strings?
The memory can't be infinite. So, the answer is NO. Even if you have every large memory, you will need a processor that could address that huge memory space. There is a limit on amount of dynamic memory that can be allocated by malloc and the amount of static memory(allocated at compile time) that can be allocated. malloc function call will return a NULL if there is no suitable memory block requested by you in the heap memory.
Assuming that you have very large memory space available to you relative to space required by your input strings and you will never run out of memory. You can store your input strings using 2 dimensional array.
C does not really have multi-dimensional arrays, but there are several ways to simulate them. You can use a (dynamically allocated) array of pointers to (dynamically allocated) arrays. This is used mostly when the array bounds are not known until runtime. OR
You can also allocate a global two dimensional array of sufficient length and width. The static allocation for storing random size input strings is not a good idea. Most of the memory space will be unused.
Also, C programming language doesn't have string data type. You can simulate a string using a null terminated array of characters. So, to dynamically allocate a character array in C, we should use malloc like shown below:
char *cstr = malloc((MAX_CHARACTERS + 1)*sizeof(char));
Here, MAX_CHARACTERS represents the maximum number of characters that can be stored in your cstr array. The +1 is added to allocate a space for null character if MAX_CHARACTERS are stored in your string.

Got "invalid next size" when executing free()

I was trying to learn the memory management of c.
I allocated the memory for
1. char** a
2. char** b
3. char* b[0] ~ b[99]
and
I freed the memory for
1. char** a
2. char* b[0] ~ b[99]
3. char** b
However, I got an error at the line33, which is free(b[0])
Why does it produces invalid next size free (fast)?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char** a = (char**)malloc(100 * sizeof(char*));
a[0] = "Hello Again!";
char** b = (char**)malloc(100 * sizeof(char*));
int i = 0;
for(i = 0; i < 100; i++){
b[i] = (char*)malloc(10 * sizeof(char));
}
strcpy(b[0], *a);
free(a);
printf("%s", b[0]);
for(i = 0; i < 100; i++){
free(b[i]);
}
free(b);
return 0;
}
The string "Hello Again!" is 13 characters long (including the terminating \0).
The memory you allocate for it is not enough (you allocate just 10 chars), so when calling strcpy you are overwriting past the allocated memory, and probably overwriting the memory location used by the library to keep track of allocations.
The next time that the library will try and use the information stored there, it finds that it is inconsistent, so it aborts with the error you mentioned. That is only one of the many messages that the library can print if it is able to find any such discrepancy.
In general, do not rely on the library flagging those errors for you: in this case you were "lucky" that the info were corrupted in a recognizable way. If you are unlucky, your program might just exhibit undefined behavior.
For each b[i], you only allocate space for 10 chars, but the strcpy copies the string "Hello Again!", which is certainly more than 10 chars. This is undefined behavior.
When you execute this line,
strcpy(b[0], *a);
you are writing over memory that you were not supposed to use. That leads to undefined behavior.
Some environments store useful information at the end of the allocated block of memory. By writing over that memory, you have destroyed that useful information.
The error is this line:
strcpy(b[0], *a);
You allocate 10 bytes for b[0], but you copy 13 bytes, thereby writing beyond the end of the allocated memory.
It's a buffer overrun because strlen(a[0]) + 1 > 10. You need to allocate more than 10 characters for b[0], specifically at least strlen(a[0]) + 1.

How do I make a function return a pointer to a new string in C?

I'm reading K&R and I'm almost through the chapter on pointers. I'm not entirely sure if I'm going about using them the right way. I decided to try implementing itoa(n) using pointers. Is there something glaringly wrong about the way I went about doing it? I don't particularly like that I needed to set aside a large array to work as a string buffer in order to do anything, but then again, I'm not sure if that's actually the correct way to go about it in C.
Are there any general guidelines you like to follow when deciding to use pointers in your code? Is there anything I can improve on in the code below? Is there a way I can work with strings without a static string buffer?
/*Source file: String Functions*/
#include <stdio.h>
static char stringBuffer[500];
static char *strPtr = stringBuffer;
/* Algorithm: n % 10^(n+1) / 10^(n) */
char *intToString(int n){
int p = 1;
int i = 0;
while(n/p != 0)
p*=10, i++;
for(;p != 1; p/=10)
*(strPtr++) = ((n % p)/(p/10)) + '0';
*strPtr++ = '\0';
return strPtr - i - 1;
}
int main(){
char *s[3] = {intToString(123), intToString(456), intToString(78910)};
printf("%s\n",s[2]);
int x = stringToInteger(s[2]);
printf("%d\n", x);
return 0;
}
Lastly, can someone clarify for me what the difference between an array and a pointer is? There's a section in K&R that has me very confused about it; "5.5 - Character Pointers and Functions." I'll quote it here:
"There is an important difference between the definitions:
char amessage[] = "now is the time"; /*an array*/
char *pmessage = "now is the time"; /*a pointer*/
amessage is an array, just big enough to hold the sequence of characters and '\0' that
initializes it. Individual characters within the array may be changed but amessage will
always refer to the same storage. On the other hand, pmessage is a pointer, initialized
to point to a string constant; the pointer may subsequently be modified to point
elsewhere, but the result is undefined if you try to modify the string contents."
What does that even mean?
For itoa the length of a resulting string can't be greater than the length of INT_MAX + minus sign - so you'd be safe with a buffer of that length. The length of number string is easy to determine by using log10(number) + 1, so you'd need buffer sized log10(INT_MAX) + 3, with space for minus and terminating \0.
Also, generally it's not a good practice to return pointers to 'black box' buffers from functions. Your best bet here would be to provide a buffer as a pointer argument in intToString, so then you can easily use any type of memory you like (dynamic, allocated on stack, etc.). Here's an example:
char *intToString(int n, char *buffer) {
// ...
char *bufferStart = buffer;
for(;p != 1; p/=10)
*(buffer++) = ((n % p)/(p/10)) + '0';
*buffer++ = '\0';
return bufferStart;
}
Then you can use it as follows:
char *buffer1 = malloc(30);
char buffer2[15];
intToString(10, buffer1); // providing pointer to heap allocated memory as a buffer
intToString(20, &buffer2[0]); // providing pointer to statically allocated memory
what the difference between an array and a pointer is?
The answer is in your quote - a pointer can be modified to be pointing to another memory address. Compare:
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
int *ptrA = &a[0]; // the ptrA now contains pointer to a's first element
ptrA = &b[0]; // now it's b's first element
a = b; // it won't compile
Also, arrays are generally statically allocated, while pointers are suitable for any allocation mechanism.
Regarding your code:
You are using a single static buffer for every call to intToString: this is bad because the string produced by the first call to it will be overwritten by the next.
Generally, functions that handle strings in C should either return a new buffer from malloc, or they should write into a buffer provided by the caller. Allocating a new buffer is less prone to problems due to running out of buffer space.
You are also using a static pointer for the location to write into the buffer, and it never rewinds, so that's definitely a problem: enough calls to this function, and you will run off the end of the buffer and crash.
You already have an initial loop that calculates the number of digits in the function. So you should then just make a new buffer that big using malloc, making sure to leave space for the \0, write in to that, and return it.
Also, since i is not just a loop index, change it to something more obvious like length:
That is to say: get rid of the global variables, and instead after computing length:
char *s, *result;
// compute length
s = result = malloc(length+1);
if (!s) return NULL; // out of memory
for(;p != 1; p/=10)
*(s++) = ((n % p)/(p/10)) + '0';
*s++ = '\0';
return result;
The caller is responsible for releasing the buffer when they're done with it.
Two other things I'd really recommend while learning about pointers:
Compile with all warnings turned on (-Wall etc) and if you get an error try to understand what caused it; they will have things to teach you about how you're using the language
Run your program under Valgrind or some similar checker, which will make pointer bugs more obvious, rather than causing silent corruption
Regarding your last question:
char amessage[] = "now is the time"; - is an array. Arrays cannot be reassigned to point to something else (unlike pointers), it points to a fixed address in memory. If the array was allocated in a block, it will be cleaned up at the end of the block (meaning you cannot return such an array from a function). You can however fiddle with the data inside the array as much as you like so long as you don't exceed the size of the array.
E.g. this is legal amessage[0] = 'N';
char *pmessage = "now is the time"; - is a pointer. A pointer points to a block in memory, nothing more. "now is the time" is a string literal, meaning it is stored inside the executable in a read only location. You cannot under any circumstances modify the data it is pointing to. You can however reassign the pointer to point to something else.
This is NOT legal -*pmessage = 'N'; - will segfault most likely (note that you can use the array syntax with pointers, *pmessage is equivalent to pmessage[0]).
If you compile it with gcc using the -S flag you can actually see "now is the time" stored in the read only part of the assembly executable.
One other thing to point out is that arrays decay to pointers when passed as arguments to a function. The following two declarations are equivalent:
void foo(char arr[]);
and
void foo(char* arr);
About how to use pointers and the difference between array and pointer, I recommend you read the "expert c programming" (http://www.amazon.com/Expert-Programming-Peter-van-Linden/dp/0131774298/ref=sr_1_1?ie=UTF8&qid=1371439251&sr=8-1&keywords=expert+c+programming).
Better way to return strings from functions is to allocate dynamic memory (using malloc) and fill it with the required string...return this pointer to the calling function and then free it.
Sample code :
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX_NAME_SIZE 20
char * func1()
{
char * c1= NULL;
c1 = (char*)malloc(sizeof(MAX_NAME_SIZE));
strcpy(c1,"John");
return c1;
}
main()
{
char * c2 = NULL;
c2 = func1();
printf("%s \n",c2);
free(c2);
}
And this works without the static strings.

Resources