What is happening to my pointer after this print statement? [duplicate] - c

I am new to C, I have mostly worked with c++ and c#. Now I am trying to write a function that reads from a file and stores the value in a string, it works within the function but when I try to pass the value out it comes out as nothing or garbage. Is there something I am missing about how C works? Here is an example of what is going wrong.
#include <stdlib.h>
#include <stdio.h>
void getArray(char**);
int main()
{
char* myArr[2];
getArray(myArr);
for(int i = 0; i < 2; i++)
{
printf("%d\n", i);
printf("%s\n", myArr[i]);
}
printf("printing done\n");
return 0;
}
void getArray(char* arr[])
{
arr[0] = "poo";
char str[6];
FILE* fp;
fp = fopen("input.txt", "r");
if(fp != NULL)
{
fscanf(fp,"%s",str);
fclose(fp);
}
arr[1] = str;
printf("%s\n", arr[1]);
}
that is the code, and here is the output
123456
0
poo
1
printing done
and here is the expected output
123456
0
poo
1
123456
printing done
sorry if am being redundant I just want to be thorough in my confusion

The problem is that you save the contents of the file to a local variable. Local variables will cease to exist after exiting the function.
Explanation:
Inside main you have this:
addr | var | value
...
0001 | --- | -----
inside main --> 0000 | arr | -----
When you enter a function, your local variables are pushed to the stack:
addr | var | value
...
inside function --> 0001 | str | -----
0000 | arr | -----
You read str and points arr to the local variable str
addr | var | value
...
inside function --> 0001 | str | 123456
0000 | arr | points to 0001
When you leave the function, str will be removed from stack
addr | var | value
...
0001 | --- | -----
after function --> 0000 | arr | points to 0001
So the variable str does not exist anymore, and when you try to do arr[1] you are getting garbage.
You can either allocate space for your variable dinamically or load the contents of the file directly to an outside variable, making sure that it will have enough space.
To allocate an array of 6 chars dinamically, use: char *str = malloc(6 * sizeof(char)) inside your function.
To use an outside variable, simply move char str[6]; to main, and pass it as parameter to the function:
void getArray(char* arr[], char* str), this way you would be able to change the value of str and still keep its value.

replace char str[6]; with char *str = malloc(sizeof(char)*7)
this way str keeps a place in memory after the function returns

Related

Why is the pointer no longer referencing the memory it was assigned?

I am new to programming and I am watching a tutorial on pointers to understand how they work. In the tutorial, the instructor stated the following:
The for-loop assigns values to the address of pointer p. Then the address stored in pointer p is incremented at line 21 to the next integer chunk. This approach works but what happens to pointer p? Its reference is gone. After the for-loop, pointer p no longer references the allocated chunk of memory.
the instructor proceeds to the next lesson without explaining how the reference is gone. Can someone explain how the pointer is no longer referencing the memory it was assigned?
P.S. This is my first time using StackOverflow. Tips on how to correctly ask questions would be appreciated if I posted this one incorrectly.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p,x;
/* allocate storage */
p = (int *)malloc( sizeof(int) * 10 );
if( p==NULL )
{
fprintf(stderr,"Allocation failure\n");
exit(1);
}
/* fill storage */
for( x=0; x<10; x++ )
{
*p = x * 100;
/* reference the next integer location */
p++;
}
puts("Memory allocated and filled");
return(0);
}
Disclaimer: This code does not belong to me. I do not take credit for it.
After it calls malloc(), p points to the beginning of the int array that was allocated.
During the loop, it uses p++ to make it point to the next element of the array. At the end of the loop, it points to the address just past the last value in the array. So it no longer points to the beginning of the array.
If you want to do anything more with the array, such as print the contents, return it to a caller, or free it, you need the original pointer to the beginning of the allocated memory. So you need another variable that isn't updated during the loop.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p,x,*original_p;
/* allocate storage */
p = (int *)malloc( sizeof(int) * 10 );
original_p = p;
if( p==NULL )
{
fprintf(stderr,"Allocation failure\n");
exit(1);
}
/* fill storage */
for( x=0; x<10; x++ )
{
*p = x * 100;
/* reference the next integer location */
p++;
}
puts("Memory allocated and filled");
free(original_p);
return(0);
}
Alternatively, you can use array indexing rather than incrementing the pointer:
for( x=0; x<10; x++ )
{
p[x] = x * 100;
}
At the start of each for loop iteration, p points to somewhere in memory; that location gets assigned a value, and then p is changed so it no longer points to that location.
In the for loop the pointer p is incremented 10 times.
for( x=0; x<10; x++ )
{
*p = x * 100;
/* reference the next integer location */
p++; // <===
}
So after the for loop it does not point to the allocated memory because the memory was allocated exactly for 10 elements. That is now the pointer p points to beyond the allocated array.
What he's talking about is that once the pointer is incremented the block of memory allocated can't be freed because it no longer points to p[0]. Keep in mind that int *p and p[0] mean the same thing in this example. So he's essentially asking "how do we free p now that we've lost track of it?". Too bad he didn't expand on that before he moved on because it would have made more sense to you.
The simplest thing to do would just be to make another that you can use to move around in the array with then go back to the original pointer when you are done with it. Like this:
int *p = malloc(sizeof(int) * 10);
int *cp = p; /* current location */
Then move cp around as you see fit, incrementing, decrementing, etc. And when you are done with cp you free(p)
Let's think abut creating a string, by hand. As you may know, a string in C is just an array of characters, terminated by a special "null" character. Here's a very simple example, which I encourage you to experiment with:
char string1[10];
char *p = string1;
*p++ = 'a';
*p++ = 'b';
*p++ = 'c';
*p = '\0'; /* this is the special "null character" terminator */
printf("%s\n", string1); /* prints "abc" */
In this example, the pointer p steps along the first few cells of the array string1, filling in characters. Then, we print out the string we've just constructed.
Here is a second example of almost the same thing, except that we call malloc to obtain some dynamically-allocated memory to construct the string, rather than using an array:
char *string2 = malloc(10);
if(string2 == NULL) {fprintf(stderr, "out of memory!\n"); exit(1); }
char *p = string2;
*p++ = 'a';
*p++ = 'b';
*p++ = 'c';
*p = '\0';
printf("%s\n", string2);
This second example works almost exactly the same way the first one does, and it also prints "abc".
Now, finally, here is a third example. Pay attention to the differences.
char *p = malloc(10);
if(p == NULL) {fprintf(stderr, "out of memory!\n"); exit(1); }
*p++ = 'a';
*p++ = 'b';
*p++ = 'c';
*p = '\0';
/* but now how can we print the string? */
In the second example, the pointer string2 still pointed at the beginning of the allocated region, which was the beginning of the string we constructed, so it was possible to print it. In this third example, we have no record of that pointer, so we have no direct way to print the string.
Theoretically, since we know how many characters we placed in the string, we could cheat, and print it like this:
printf("%s\n", p - 3); /* DANGEROUS */
But this is a silly and dangerous thing to do. Normally, the thing to do is keep one pointer pointing to the beginning of the string, and use another to step along it -- that is, as we did in the second exampe, with string2.
The variable p itself is only a pointer to some memory. It can't point to ten things at once, only one single thing.
And what is pointing at (initially!) is the first element of the "array" that you've allocated with malloc. After doing p++ once, then p is pointing to the second element, and so on.
Somewhat graphically it's like this:
+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+---+---+---+---+---+---+---+---+---+---+
^
|
+---+
| p |
+---+
This is directly after the call to malloc. The number are the indexes of the elements.
Now if we do p++ once it will look like this instead:
+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+---+---+---+---+---+---+---+---+---+---+
^
|
+---+
| p |
+---+
Then after a second p++:
+---+---+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+---+---+---+---+---+---+---+---+---+---+
^
|
+---+
| p |
+---+
And so on...

if i assign pointer 1 to be equal to pointer 2 and then change pointer 2 does pointer 1 change?

I've written the follwing function:
int read_words(char* words[], int size, int max_str_len)
{
char* pointers = (char*)malloc(max_str_len * sizeof(char) +1); // the + 1 is for the null
terminator
if(pointers==NULL)
{
free(pointers);
return -1;
}
int i=0;
int j=1;
while((i<size ) && (scanf("%c", & *pointers) != EOF ))
{
while(scanf("%c", & *(pointers + j)) != ' ' && j<max_str_len)
{
j++;
}
*(pointers + j) ='\0';
words[i] = pointers;
j=0;
i++;
}
free(pointers);
return i;
}
which is supposed to read a bunch of strings (which is in C language defined as an array of chars) and assign them pointers from the array words. (the strings' max length is max_str_len)
then i tried using it in the following loop:
while(i<num_words)
{
while(*(words[i]+j) != '\0')
{
*(words[i]+j) = encrypt(key, *(words[i]+j));
j++;
}
j=0;
i++;
}
where encrypt gets a key array and encrypts each char it gets based on the array.
For some reason the program gets terminated after recieving the input for the array words (so I think the problem is in the function read_words, I'm not sure the function is actually scanning the words.
note: others who tried helping me with the function said that I should scan the words as whole not as individual chars but the function's time complexity is supposed to be O(size*max_str_len) and if I don't scan them as chars it won't meet the conditions.
to be honest I'm not sure how to use malloc, I can't seem to find the mistakes of the code.
I also have a general question about malloc:
If p is a dynamic allocation of a certain bytes size, and arr is an array of pointers: 
If p is pointing at a specific variable and we define arr[0] to be equal to p, then we change p to be a different variable, does arr[0] still point to the first variable? Or is its value lost and now arr[0] isn’t pointing at anything or pointing at the new variable? 
Meaning in the function above:
If I define p to be:
char* p = (char*)malloc(max_atr_len*sizeof(char));
And then I scan the words as following: 
scanf(“%s”, & p);
And then I write: 
words[i] = p;
If I then scan a different word, is the value of the first word lost or does words[i] still point at it? 
Any help is very much appreciated :)
After assignment both pointers point to the same data object, but you are free to change each pointer to point somewhere else without affecting the other pointer.
scanf("%s", p); doesn't change p. It changes that to which p points.
words[0] = p; only copies the value of p (the address), nothing more.
Let's consider the following snippet:
char* p = malloc(...);
scanf("%s", p);
words[0] = p;
scanf("%s", p);
words[1] = p;
p is only changed by the first line, so p, words[0] and words[1] all have the same value: the address of the memory block you allocated.
The only memory block was populated by the first call to scanf, and overwritten by the second call to scanf.
words malloc'ed block
+----------+ +---+---+---+---+---+---+---+--...
| --------+-->| I | n | p | u | t | 2 | ␀ |
+----------+ | +---+---+---+---+---+---+---+--...
| --------+
+----------+ |
|
|
p |
+----------+ |
| --------+
+----------+
Now let's consider the following snippet:
char* p = malloc(...);
scanf("%s", p);
words[0] = p;
p = malloc(...);
scanf("%s", p);
words[1] = p;
The value of words[0] is the address of the first memory block you allocated.
The value of words[1] is the address of the second memory first block you allocated.
and
The first memory block you allocated was populated by the first call to scanf.
The second memory block you allocated was populated by the second call to scanf.
words First malloc'ed block
+----------+ +---+---+---+---+---+---+---+--...
| ----------->| I | n | p | u | t | 1 | ␀ |
+----------+ +---+---+---+---+---+---+---+--...
| --------+
+----------+ | Second malloc'ed block
| +---+---+---+---+---+---+---+--...
+-->| I | n | p | u | t | 2 | ␀ |
p | +---+---+---+---+---+---+---+--...
+----------+ |
| --------+
+----------+
By the way, note that your use of scanf is unsafe. Bad things will happen if the input is larger than you anticipate.

Correct way to pass the char pointer to helper fuction and assign the value in C

I have some questions regarding assign the value to a char* in a helper function. If I have following code
int main() {
char *p = malloc(6* sizeof(char));
changeValue(p);
printf("value of p=%s\n", p);
return 0;
}
If I define following function, then it doesn't work:
void changeValue(char* input){
input = "hello";
}
My first quesiton is what is the reason we can't assign a value directly to a pointer?
My previous understanding is because the space "hello" is created only during the changeValue scope and once it is out of the changeValue function, It is destroyed. However if I use the pointer of pointer to assign the value it works. Seems like "hello" space is not destroyed:
void changeValue(char ** input){
*input = "hello";
}
In the main I need to change to:
char **p2 = malloc(sizeof(char*));
changeValue(p2);
printf("value of p2=%s\n", *p2);
And it works properly. My second question is what happened to the second function to make it work properly and which part is wrong in my previous logic?
I also find the following way to assign the value:
The changeValue function keep the same:
void changeValue(char ** input){
*input = "hello";
}
In the main cpp I did following:
char *p = malloc(6* sizeof(char));
changeValue(&p);
printf("value of p=%s\n", p);
Seems like it also works properly but it doesn't make any sense to me. My third question is the input is the address of the p in memory, how dereference the address and assign a value to it works?
And what is the correct approach to assign a char* value in the helper function?
Thanks
In the first version, 'p' points to malloc'ed memory (6 bytes). In the 2nd version, p2 points to memory that will contain an address.
In the 1st version of your helper function:
void changeValue(char* input){
input = "hello";
}
Outside of that function, 'p' is still pointing to the malloc'ed memory. When the program enters the changeValue() function, the value of 'p' is pushed onto the stack, where it is now referenced by a new field called 'input'... that only exists on the stack. So by assigning it the literal "hello", you have replaced 'p' with the address of the string literal "hello".
Meanwhile, the location of 'p' is NOT the same as 'input'. Once the function returns, the memory temporarily assigned to 'input' has been popped and is no longer relevant.
Maybe a diagram can help:
At first:
char *p = malloc(6* sizeof(char));
(Stack) (Heap)
+-------+ +------------------+
| p +--------> | 6 * sizeof(char) |
+-------+ +------------------+
Next, the call to:
changeValue(p); // first version
affects the following:
(Stack) (Heap)
+-------+
| input +----+
+-------+ | +------------------+
| p +----+---> | 6 * sizeof(char) |
+-------+ +------------------+
and then:
input = "hello";
(Stack) (Heap) (DataSegment)
+-------+ +-------+
| input +----------------------------------->|"hello"|
+-------+ +------------------+ +-------+
| p +-----> | 6 * sizeof(char) |
+-------+ +------------------+
and upon exit from 'changeValue', the stack is unwound and 'input' is no longer relevant.
(Stack) (Heap)
+-------+ +------------------+
| p +--------> | 6 * sizeof(char) |
+-------+ +------------------+
and in the end of the main function, you now have a memory leak (the malloc'ed memory has not been freed).
One correct way to use the helper function is:
int main() {
char *p = malloc(6* sizeof(char));
changeValue(p, 6* sizeof(char) );
printf("value of p=%s\n", p);
free( p ) ; // <<<<<< avoid memory leak
return 0;
}
void changeValue(char * input, size_t maxSize){
// ... Copy "hello" into the space pointed to by input, taking
// care not to overrun the memory
strncpy( input, "hello", maxSize ) ;
}
As to this question, I think the memory that stores the pointer s, whose size is dependent on the system, with the memory that the pointer s points to, which is 6 bytes big allocated, are two different concepts.
“The third bit of code (char p = malloc(6 sizeof(char)); changeValue(&p);) is wrong because the memory pointed to by p might not be large enough to hold a pointer. On systems with 64-bit pointers, sizeof(char *) is typically 8, which is greater than the 6 * sizeof(char) you allocated. By the way, sizeof(char) is 1 by definition, so malloc(6 * sizeof(char)) is the same as malloc(6). ”

Allocating a fixed character array vs. a pointer for casting to string

I'm new to C, and trying to understand why the following works with a fixed-size character array but not with a pointer:
float number = 1245.12;
// allocate a character array for the buffer
char number_as_string[50];
sprintf(number_as_string, "%f", number);
But allocating a pointer (which I thought would point to a location in memory, and allow iterating to the next memory point, etc.) would not work:
float number = 1245.12;
// allocate a pointer
char * number_as_string;
sprintf(number_as_string, "%f", number);
I'm going to answer your question in two parts.
You wrote
float number = 1245.12;
char number_as_string[50];
sprintf(number_as_string, "%f", number);
That's fine and will work, although of course one problem with fixed-size buffers like these is that it's easy to overflow them, sometimes with catastrophic results. So a preferred alternative is
snprintf(number_as_string, sizeof(number_as_string), "%f", number);
snprintf is a variant of sprintf that lets you specify the size of the buffer. That way, snprintf can take care not to write more characters to the buffer than it will hold.
So now let's see about using snprintf with your second example:
char *number_as_string;
snprintf(number_as_string, ???, "%f", number);
But what size do we use? How big is the buffer pointed to by this second number_as_string? We don't know, and this helps us realize that we haven't yet allocated a buffer for the second number_as_string to point to at all.
What you want to do is use malloc to allocate some memory for number_as_string to point to:
number_as_string = malloc(50);
Now, and assuming malloc succeeds, you know what number to hand to snprintf as the buffer size:
snprintf(number_as_string, 50, "%f", number);
Realistically, of course, we'd have a variable holding the allocated buffer size, rather than repeating the number "50" in multiple places. So here's the more realistic example, including the test to make sure malloc didn't fail:
int buffer_size = 50;
char *number_as_string = malloc(buffer_size);
if(number_as_string == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
snprintf(number_as_string, buffer_size, "%f", number);
Just make sure you don't do:
snprintf(number_as_string, sizeof(number_as_string), "%f", number);
when number_as_string is a pointer. In that case, you'll get the size of the pointer (typically 4 or 8 bytes, these days), not the size of the pointed-to buffer, which is what you want.
I like to understand memory allocation, and pointers, with little box-and-arrow diagrams. Here's char number_as_string[50]:
+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+
number_as_string: | | | | | | | | | | | | | |...| | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+
Here's char *number_as_string followed by a successful number_as_string = malloc(50):
+-------+
number_as_string: | * |
+---|---+
|
v
+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+
| | | | | | | | | | | | | |...| | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+
But here's char *number_as_string all by itself:
+-------+
number_as_string: | *--------> ???
+-------+
The arrow -- the pointer -- points "nowhere".
A pointer variable needs something to point to, and in your second example number_as_string doesn't point to anything. Attempting to dereference it via a call to sprintf invokes undefined behavior.
You need to either allocate space dynamically:
char * number_as_string = malloc(50);
Or make it point someplace valid:
char str[50];
char * number_as_string = str;
In the first case
char number_as_string[50];
sprintf(number_as_string, "%f", 123.456);
you have an automatic-storage variable that is an array of 50 chars. This array is usualy on the stack, so when you call sprintf(), you are "printing" on valid memory.
In the second case
char * number_as_string;
sprintf(number_as_string, "%f", 123.456);
you also have an automatic variable. However this variable is only a pointer. You did not ask the compiler for an array. Furthermore, you didn't initialize the pointer, so you cannot even tell whether sprintf() will even receive a memory location that belongs to your program.
This is what you are looking for:
char * number_as_string = malloc(50);
sprintf(number_as_string, "%f", 123.456);

In C, I have an array of char* that I read from a file, when I pass it out of the function by refenrce I get garbage

I am new to C, I have mostly worked with c++ and c#. Now I am trying to write a function that reads from a file and stores the value in a string, it works within the function but when I try to pass the value out it comes out as nothing or garbage. Is there something I am missing about how C works? Here is an example of what is going wrong.
#include <stdlib.h>
#include <stdio.h>
void getArray(char**);
int main()
{
char* myArr[2];
getArray(myArr);
for(int i = 0; i < 2; i++)
{
printf("%d\n", i);
printf("%s\n", myArr[i]);
}
printf("printing done\n");
return 0;
}
void getArray(char* arr[])
{
arr[0] = "poo";
char str[6];
FILE* fp;
fp = fopen("input.txt", "r");
if(fp != NULL)
{
fscanf(fp,"%s",str);
fclose(fp);
}
arr[1] = str;
printf("%s\n", arr[1]);
}
that is the code, and here is the output
123456
0
poo
1
printing done
and here is the expected output
123456
0
poo
1
123456
printing done
sorry if am being redundant I just want to be thorough in my confusion
The problem is that you save the contents of the file to a local variable. Local variables will cease to exist after exiting the function.
Explanation:
Inside main you have this:
addr | var | value
...
0001 | --- | -----
inside main --> 0000 | arr | -----
When you enter a function, your local variables are pushed to the stack:
addr | var | value
...
inside function --> 0001 | str | -----
0000 | arr | -----
You read str and points arr to the local variable str
addr | var | value
...
inside function --> 0001 | str | 123456
0000 | arr | points to 0001
When you leave the function, str will be removed from stack
addr | var | value
...
0001 | --- | -----
after function --> 0000 | arr | points to 0001
So the variable str does not exist anymore, and when you try to do arr[1] you are getting garbage.
You can either allocate space for your variable dinamically or load the contents of the file directly to an outside variable, making sure that it will have enough space.
To allocate an array of 6 chars dinamically, use: char *str = malloc(6 * sizeof(char)) inside your function.
To use an outside variable, simply move char str[6]; to main, and pass it as parameter to the function:
void getArray(char* arr[], char* str), this way you would be able to change the value of str and still keep its value.
replace char str[6]; with char *str = malloc(sizeof(char)*7)
this way str keeps a place in memory after the function returns

Resources