This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 5 years ago.
I am wondering why the output is garbage? And how can I solve this problem?
#include<stdio.h>
char *Func(void);
int main()
{
char *string1;
string1 = Func();
puts(string1);
return 0;
}
char *Func(void)
{
char string2[10]="medo";
return string2;
}
Because string2 is only valid in the scope of Func.
An array decays into a pointer when assigning it to a pointer, passing it to a function or when used with return in a function returning a pointer.
An array decaying into a pointer means that it is converted to a pointer and the pointer points to the first element of the array.
With an array like this:
int arr[] = { 1, 2, 3 };
These are equivalent:
int *p1 = arr;
int *p2 = &arr[0];
The problem with Func is that it is returning a pointer that points to a memory location that is only valid while Func is running. Once Func returns, it is no longer valid and the program flow might replace these values immediately.
In your main function you pass this pointer to printf and because the location where string1 is pointing to isn't valid in main (it was only valid in Func), you get garbage. Actually that is undefined behaviour, and medo could have been printed as well.
How to fix it: declare an array in main, pass it to Func, let Func use the
passed array and return:
#include<stdio.h>
#include<string.h>
Func(char* string2);
int main()
{
char string1[20];
Func(string1);
puts(string1);
return 0;
}
void Func(char *string2)
{
strcpy(string2, "medo");
}
Because the lifetime of the string has already ended by the time you print it.
Local variables, such as string2 in Func, are often stored in the stack, which is a very dynamic structure that changes every time a function is called or returned. (The actual behavior of the program stack is a bit too complex to elaborate here, but keep in mind that stuff in the stack doesn't survive the function that puts it there.)
By the time the function returns, string2 is no longer necessary, and thus it might be overwritten with garbage data. Nevertheless, Func returns a pointer to string2 (remember that the name of an array is a pointer to its contents) — thus returning a pointer to the stack-allocated string that is being overwritten with garbage data. Printing the data referenced by this pointer (in main, via string1) just prints that garbage.
There are two ways of solving this issue. One is to let the caller handle memory allocation, and pass the allocated area to the callee, like so:
#include <stdio.h>
#include <string.h>
void Func(char *);
int main (void) {
char string[10];
Func(string);
puts(string);
return 0;
}
void Func (char * string) {
strcpy(string, "test");
}
...and another way is to let the callee handle the allocation, but remembering that the caller must free it, like so:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * Func(void);
int main (void) {
char * string = Func();
puts(string);
free(string);
return 0;
}
char * Func (void) {
char * string = malloc(10);
strcpy(string, "test");
return string;
}
Either way would solve your issue, and which one you choose is a matter of design.
Related
This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 1 year ago.
#include <stdio.h>
#include <stdlib.h>
void allocateMem(int *a)
{
a = (int*)malloc(5 * sizeof(int));
}
int main()
{
int *ptr;
allocateMem(ptr);
ptr[0] = 5454;
ptr[1] = 54;
printf("Hi %d\n", ptr[1]);
free(ptr);
return 0;
}
I didn't get any output and error with the code. But if I allocate memory in main function, it actually works.
C function arguments are passed by value. This means that when you pass ptr to allocateMem and then modify it within allocateMem, you're not changing anything about ptr.
You are creating a memory leak, since you can't free the memory you've dynamically allocated as you haven't preserved a pointer to it.
Any argument you want a function to modify external to the function you're calling, you need to pass a pointer to, so if you want to modify a pointer, you need to pass a pointer to a pointer, as #babon has demonstrated with the code in their answer.
Here's the fix:
#include <stdio.h>
#include <stdlib.h>
void allocateMem(int **a)
{
*a = malloc(5 * sizeof(int));
}
int main()
{
int *ptr;
allocateMem(&ptr);
ptr[0] = 5454;
ptr[1] = 54;
printf("Hi %d\n", ptr[1]);
free(ptr);
return 0;
}
To write to a variable in another function, you need to pass a pointer to it. Since the intention here is to write to a pointer, you need to pass the address of the pointer - &ptr.
As an address was passed, the allocateMem() function dereferences a once to hop into the memory location which is to be updated and lays down the address returned by malloc(). When this function returns, main() finds that ptr is pointing to a valid address and writes data inside the allocated memory.
You can return the pointer to the allocated memory (and check the return value), like this:
#include <stdio.h>
#include <stdlib.h>
int *allocateMem(void)
{
return (int*)malloc(5 * sizeof(int));
}
int main()
{
int *ptr;
if( NULL != (ptr = allocateMem()))
{
ptr[0] = 5454;
ptr[1] = 54;
printf("Hi %d\n", ptr[1]);
free(ptr);
}
return 0;
}
The constant number 5 in allocateMem should not be hardcoded, or give it a valuable name.
In the code, I wanted to reverse the string.
However, the function call changed the value of string A in the main function as well (The function is correct but I don't know why the function is changing the actual value of the string in the main function)
How could I reverse the string in revstr without modifying A from main?
#include<stdio.h>
#include<string.h>
void revstr(char A[], int l);
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr(A,l);
printf("%s", A);
return 0;
}
void revstr(char A[], int l){
int x=0,y,temp;
y=l-1;
while(x<y){
temp=A[x];
A[x]=A[y];
A[y]=temp;
x++;
y--;
}
printf("%s", A);
}
You are passing the array to the function call, (i.e., the pointer to the first element of the array), and from the called function, you're actually changing the contents of the memory locations.
The changes to these memory locations are not of a copy of the original array, rather taking place in the actual array itself. So, the changes made from the called function are reflecting in the caller function also. The actual array itself is getting modified, so when you try to print the array in the main() function, it already has it's contents modified, and that modified content is getting printed.
You need to keep a copy of the original array in the caller, if you want to refer the unmodified version later.
Be aware that what You are calling a string, really is an array of characters. As a consequence in the function You are not actually passing a string, but the location in memory (a pointer) of the first element of the char array.
So whats being manipulated in the function is whatever is stored at that specific location.
One way to work around this would be to pass an additional, empty array to the function in which the reversed string is stored.
When a function is called the arguments are evaluated and each parameter is assigned the value of the corresponding argument.
For example you can imagine the definition if the function revstr and its call in main the following way (for clarity I renamed function parameters like F_A and F_l)
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr(A,l);
//...
void revstr( /*char F_A[], int F_l */ )
{
char F_A[] = A;
int F_l = l;
//...
That is the function parameters are initialized by the values of the argument expressions.
But here is a problem. In this declaration
char F_A[] = A;
we are trying to initialize an array with an array designator something like
char A[] = "Hello";
char F_A[] = A;
Such an initialization is incorrect. You may initialize a character array either with a string literal or with a braced list of initializers.
So how is this problem resolved in C?
For starters the compiler adjusts function parameters that have array types to pointers to array element types. Thus this function declaration
void revstr(char A[], int l);
is adjusted by the compiler to the declaration
void revstr(char *A, int l);
and the both declarations declare the same one function. You may include the both declarations of the function in your program though the compiler can issue a message that there are redundant function declarations.
On the other hand, when an array is used as an argument expression it is also implicitly converted to pointer to its first element.
So in fact you have
void revstr( char *A, int l );
int main(){
char A[20];
scanf("%s", A);
int l=strlen(A);
revstr( &A[0], l );
//...
So within the function you are dealing with a pointer that points to the memory extent where the elements of the array A declared in main are situated. Using this pointer you are changing these elements that is the original array declared in main.
In fact the elements of the array A is passed to the function through a pointer to them. Such passing objects through pointers to them in C is called passing by reference. Using the pointers you have a direct access to the objects pointed to by the pointers.
Pay attention that that it is better to declare and define the function revstr the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
char * revstr( char *s, size_t n )
{
if ( n != 0 )
{
for ( size_t i = 0; i < --n; i++ )
{
char c = s[i];
s[i] = s[n];
s[n] = c;
}
}
return s;
}
int main(void)
{
char s[20];
scanf( "%19s", s );
size_t n = strlen( s );
puts( revstr( s, n ) );
return 0;
}
The program output might look like
Stackoverflow
wolfrevokcatS
That is the second parameter of the function revstr shall have the type size_t instead of the type int because size_t is the return type of the function strlen.
The function should return the pointer to the first character of the reversed array.
Will this code give a Buffer overflow crash?
#include <stdio.h>
void show(char text[2]) {
printf("%c%c\n", text[0], text[1]);
return;
}
int main() {
char *txt = "aabc";
show (txt);
return 0;
}
I mean txt has 4 characters (plus '\0'), while text has only 2.
Arrays are passed in C by reference, this means when a function accepts an array as an argument it does not get a copy of that array, but rather a pointer to it.
So in your case char text[2] is not a new copy of txt in main, but rather a pointer to it. Thus you will not get an overflow as you are not trying to copy the contents of txt into char text[2], text just points to it.
For example the output of the following is 13
void test(char a[2]){
printf("%d", strlen(a));
}
int main(){
char* text = "Hello World!\n";
test(text);
}
You are mistaken.
The compiler implicitly adjusts a parameter declared like an array to pointer to the array element type.
So this declaration
void show(char text[2]);
is equivalent to the declaration
void show(char *text );
You could even declare the function like
void show(char text[1000]);
In any case the compiler will adjust it to the declaration
void show(char *text );
That is the function deals with a pointer to the first element of the array passed to the function as an argument or with the value of the passed pointer as an argument.
So neither overflow occurs. The string literal itself is not moved from one part of memory to another. It is the value of the pointer that is passed to the function.
It is your responsibility not to access the passed string beyond the allocated memory for it.
This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 9 years ago.
I have to know size of an array after passing it to a function. For example,
#include<stdio.h>
void func(char *ptr)
{
printf("%d\n",------); //Here i want the actual size of the array passed to ptr. What to fill in the blank to get total size of the arr[]
}
main()
{
char arr[10] = "Hello";
printf("%d\n",sizeof(arr)); // here it is giving 10 bytes that is equal to total size of the array
func(arr);
}
No you can't, the compiler doesn't know that the pointer at the function is pointing to an array, there are some solutions though, I can state:
1) pass the length with the function parameters :
void func(char *ptr, int length)
{
printf("%d\n",length);
}
2) if your array is always of type char, you can put a NULL char ('\0') and the use strlen
#include <stdio.h>
#include <string.h>
void func(char *ptr)
{
printf("%zu\n",strlen(ptr) + 1);
}
int main()
{
char arr[10] = {10,2,11,223,4,45,57,11, 12 ,'\0'};
printf("%zu\n",sizeof(arr));
func(arr);
}
// prints
//10
//10
Cheers
No way. You have to pass the size of array too. When you are passing an array to a function then actually you are passing pointer to its first element. In this case size of array is not known to the function.
Arrays decays into pointers when you pass to a function. With pointer alone, you can not get the size of the array. You have to pass one more argument to the calling function which is the size of the array.
Example:
#include <stdio.h>
void fun(int myArray[10])
{
int i = sizeof(myArray);
printf("Size of myArray = %d\n", i);
}
int main(void)
{
// Initialize all elements of myArray to 0
int myArray[10] = {0};
fun(myArray);
getch();
return 0;
}
Here the output will be 4 (depending on the sizeof pointer on your platform, it may vary)
This is because, “arrays decays into pointers” the compiler pretends that the array parameter was declared as a pointer and hence the size of pointer is printed.
So, you have to pass the size as one more parameter to the calling function...
#include <stdio.h>
void fun(int myArray[10], int size)
{
printf("Size of myArray = %d\n", size);
}
int main(void)
{
// Initialize all elements of myArray to 0
int myArray[10] = {0};
fun(myArray, sizeof(myArray));
getchar(); ^----------------Here you are passing the size
return 0;
}
So, here the output is 40...
I have been using java for long time but for some reason I need to use C (ANSI C not C++) to write a simple code. I need to pass the pointer from outside to a function, allocate some memory to the pointer and assign some values also before the function return. I have my code like
#include <stdio.h>
#include <stdlib.h>
void test(int *a)
{
int n=3;
// I have to call another function t determine the size of the array
n = estimatesize(); // n >=3
// I tried fix size n=10 also
a = (int*)malloc(n*sizeof(int));
a[0] = 1;
a[1] = 2;
a[2] = 3;
}
void main(void)
{
int *s=NULL;
test(s);
printf("%d %d %d", s[0], s[1], s[2]);
}
I don't know why the code crashes. I thought at the beginning it is estimatesize() return wrong number but even I fix n to 10, the error still there. So I cannot pass a pointer to a function for memory allocation? If so, how can I dynamically create memory inside a function and pass it out? I know it may be a safe problem in this way but I just want to know if it is possible and how to do that. Thanks.
There are two solutions to this: Either return the pointer from the function, or pass the argument by reference.
For the first one, you simply don't take any arguments, instead you return the pointer:
int *test(void)
{
int *a = malloc(...);
...
return a;
}
int main(void)
{
int *s = test();
...
}
For the second one, you need to pass the address of the pointer, in other words a pointer to the pointer, using the address-of operator &:
void test(int **a)
{
*a = malloc(sizeof(int) * 3);
for (int i = 0; i < 3; ++i)
(*a)[i] = i;
}
int main(void)
{
int *s;
test(&s);
...
}
The reason it doesn't work now, is because the pointer (s in main) is passed by copying it. So the function test have a local copy, whose scope is only in the test function. Any changes to a in the test function will be lost once the function returns. And as s is copied for the argument, that means that s in main never actually changes value, it's still NULL after the function call.