Who initialize a char pointer inside a struct on the stack - c

Its generally known that things on the stack are not initialized by default. I tried to prove that with a struct on the stack, but unexpectedly my pointer is initialized with null, but why? What is initializing this pointer?
#include <stdio.h>
#include <string.h>
struct strustri {
int var1;
char *var2;
};
int main()
{
struct strustri test1 = {
.var1 = 12,
.var2 = "Teststring",
};
struct strustri test2;
printf("test1.var1 is %d\n", test1.var1);
printf("test2.var1 is %d\n", test2.var1);
printf("test1.var2 points to %p\n", test1.var2);
printf("test2.var2 points to %p\n", test2.var2);
return 1;
}
And this is the output on my machine (Ubuntu 12.10):
test1.var1 is 12
test2.var1 is -1271814320
test1.var2 points to 0x400634
test2.var2 points to (nil)
I ran my example multiple times. I get another value for var1 everytime, but var2 is always points to zero (null pointer)...

Nothing is initializing it.
It's just an artefact of whatever rubbish happens to be on your stack. Switch the order of the variable declarations, or add some more local variables, and you'll get a different result.

If you put your test structures in a separate function, then have another function that creates an array of char, say 200 bytes long, that you fill with some letters, and call the two functions alternating, you'll notice that your values in test2 will be different [most likely, but not 100% guaranteed - since we are dealing with "undefined behaviour", something else could happen].

when int var1 is executed to create space for test2, it has create space for itself but if you don't assign a value to it then it will show the value which was already there..
but in case of var2, it is a pointer. if pointers are not initialized then it does not point to anything, making it nil or NULL or '\0'

Related

Pass by reference for pointers in C

I was trying to understand the concept of passing by reference. When I do this,
#include<stdio.h>
int recent (int *a)
{
*a = 20;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = &bee;
printf("Value is %d\n", *val);
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
Basically I am making the pointer val point to the memory location of bee, and then when I pass it to recent function, and change the value, that change gets reflected in the calling function, so the value changes to 20. But when I do this,
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = NULL;
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
I get segmentation fault.
Is it because I didn't initialize the pointer to point to any location, and then I passed the value to recent function, and even though I made it point to a memory location (check variable), the calling function didnt catch that because I was passing by value?
Is this completely true or I misinterpreted something and got lucky with the answer?
Your problem is that you are printing the output of dereferencing the pointer val in the main function. The value of the pointer val in the main function is NULL. Thus the program is trying to print the thing at memory location 0, which is inaccessible to your program and results in a segmentation fault.
First you create the val pointer and assign it the value NULL.
int *val = NULL;
Then you call recent, passing it the pointer val, which still holds NULL.
recent(val);
Finally you print *val. val still holds NULL, and the * operator tells the compiler to "dereference" val, meaning to use the value of the thing that val is pointing to.
printf("Now Value is %d\n", *val);
In response to the question of whether your description is correct, the answer is sort of, but your description is imprecise. You made the function's copy of the pointer point to something. When you implement a pass-by-reference function in C using pointers, you are still passing the pointers themselves by value: a copy of the pointer is made, pushed onto the stack, and sent to the function. If you update the value of the pointer in the called function, the value of the pointer in the calling function will not be changed.
The reason has to do with your function recent(). When you pass in "a" you are passing in an int* (i.e. int pointer) which is an address to a location in memory. However, "a" as you have it, is local to this function (the pointer is pass by value).
Thus when you set "a = &check", you are only changing the local pointer value. As soon as recent() returns, "a" goes out of scope. In this context, you are never changing what "a" actually points to.
Thus, you segfault because val is still null, and you are trying to dereference a NULL pointer.
val is still a null pointer after leaving the function. The pointer itself is (as you correctly guessed) only passed by value, not by reference. Inside the function you are only modifying the pointer (which only lives insides the function), not the pointer target.
Besides that, please be careful with passing around memory locations to automatic stack variables. At least coming from a C++ background, it's considered bad style. Since you don't explicitly control the life cycle of a stack variable yourself (as you would do with malloc/free), you can easily shoot yourself in the foot by accidentally dereferencing pointers which have already been cleaned from the stack.
Is it because I didn't initialize the pointer to point to any location,
Code well initialized with int *val = NULL;, yet NULL is not a valid location. It isn't the NULL is a location or not. It is the NULL is the null pointer constant. As a null pointer, it "is guaranteed to compare unequal to a pointer to any object or function."
... and even though I made it point to a memory location (check variable), the calling function didn't catch that because I was passing by value?
Yes. With a = &check;, only the local a was affected, not the val in which a was copied from as the actual augment val was passed by value (copied) to the formal parameter a.
Is this completely true ...
IMO: Yes
... I misinterpreted something and got lucky with the answer?
It appears no misinterpretation. Lucky - hard to rate.
Here is what is going on in your code:
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
// memory is allocated to hold an integer
int bee;
// the number 5 is written into that memory space
bee = 5;
// memory is allocated to hold a memory address
// the value of null (which is a invalid address) is written into it
int *val = NULL;
// more memory is allocated to hold a memory address (int* a)
// the address in val (which is null) is written into it
// the new memory address (a) now points to the address of check
recent(val);
// val is still NULL
// BOOOM!
printf("Now Value is %d\n", *val);
return 0;
}
Long story short, you are correct! :)
It's basically what all have answered. It's because you are passing the address pointed by pointer a using Pass By Value method. That is your sending in a copy of the address. If you want the second code to work you need to change the code to the following,
#include<stdio.h>
int check = 20;
int recent(int **a)
{
*a = &check;
return 0;
}
int main()
{
int bee;
bee = 5;
int *val = NULL;
recent(&val);
printf("Now Value is %d\n", *val);
return 0;
}
That is you have to Pass the address pointed by a by using C version of "Pass By Reference".

c programming: casting "void pointer" to point to struct

I'm writing this program to practice C programming, this is my code:
#include <stdio.h>
#include <stdlib.h>
struct s1 {
int i;
void * p;
};
static struct s1 *dmk;
int main(void) {
int tong(int a, int b);
int (*tinh)(int,int);
struct s2 {
int num;
int (*cal)(int a, int b);
};
if(dmk->p == NULL)
{
printf("NULL ALERT\n");
}
struct s2 *cl = dmk->p;
cl->cal = tong;
tinh = ((struct s2 *)(dmk->p))->cal;
printf("tinh 2, 4 ra %d\n",tinh(2,4));
puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */
return EXIT_SUCCESS;
}
int tong(int a, int b)
{
return a + b;
}
When I compiled it, it didn't show any error or warning. But when I ran the program, the terminal told me that "core dumped" and did not show any result accept for the "NULL ALERT". Can anyone explain why I failed ? Thanks alot.
if(dmk->p == NULL)
fails as dmk is uninitialised initialised to NULL, points "no-where", so de-referencing it invokes undefined behaviour. Anything can happen afterwards.
dmk is a global (aka. static (this is not related to the static keyword!), variable, thus it is initialized to a null pointer. You do not change this value, so dkms->p dereferences a null pointer, which invokes undefined behaviour (UB).
So from here, it is speculation, as UB means anything can happen.
Apparently the printf passes, probably because the address can be read. The following write OTOH fails, generating the system messsage.
Bottom line is that what you're doing wrong is not assigning things to your various pointers before using them.
Your dmk is a global, so its initial value is NULL. You're never changing that value.
Later, you read dmk->p. You're now in Undefined Behavior (UB) territory. The program could easily have faulted right there, because you were reading from a NULL pointer.
Apparently it didn't, though, because you're seeing your NULL ALERT message, and so we continue.
Then you do this:
struct s2 *cl = dmk->p;
cl->cal = tong;
On the second line there, cl is completely indeterminate. It could be garbage, it could be NULL, whatever, because you're entered UB territory. Then you dereference it and write to the result. You could be trying to write anywhere. Writing to random pointers (or NULL pointers) tends to make core dumps and other Bad Thingsā„¢ happen.
You need to actually assign values to your pointers before you use them.
You don't initialize dmk in your code. That dmk->p is NULL is pure luck. Anything could happen.
You need to allocate memory for your struct using, for instance, malloc(), and initialize the members properly.

Assigning malloc output to an address? lvalue error

Why is it not possible to assign the malloc output to the address of a struct?
Case 1
This gives an lvalue error:
struct winErs
{
int netds;
char* blts;
};
void func_3(struct winErs gibble){
printf("this is the address of the gibble %d \n", &gibble);
&gibble = malloc(sizeof(struct winErs));
}
int main(int argc, char const *argv[])
{
struct winErs simple_Case;
func_3(simple_Case);
return 0;
}
Case 2
This does not give an error:
struct winErs
{
int netds;
char* blts;
};
void func_3(struct winErs *gibble){
printf("this is the address of the gibble %d \n", &gibble);
gibble = malloc(sizeof(struct winErs));
}
int main(int argc, char const *argv[])
{
struct winErs simple_Case;
func_3(&simple_Case);
return 0;
}
Is there a good explanation as to why this doesn't work? Thanks.
Leaving aside the language of the standard which talks about lvalues and rvalues ...
gibble already has an address. You cannot change that address. You can only change its value.
Only the value of a pointer can be changed so that it points to a different location in memory.
Even in Case 2, you are not changing the address of simple_Case in the function. You are only changing the value of the pointer in func_3. It is a local change in the function. It is a memory leak, BTW. The memory allocated by malloc is not visible to the calling function. Hence, the calling function has no way of deallocating it.
In func_3() case2, gibble begins with the address of main's simple_Case. Later it takes on the value of the pointer return by malloc(). Certainly nothing strange there, gibble is a pointer and its value changes as code proceeds.
In case1, code attempts to change the address of a variable with &gibble = malloc(). The address of variables are not change-able. Note that a variable may not even have an address if it was optimized to only exist as a processor's register.
Because the location of a value is determined by the compiler. It's not something you get to change by assignment or any other means. &gibble is the location of gibble. It's not assignable in the same sense that 1 = 42; would not change the value of the constant 1 to 42. Not assignable is the same as saying it's not an l-value.
To put it in practical terms, if you live at 1 Baker St., it would be silly to think your house would hop spontaneously across the street if someone decided to assign your address as 2 Baker St. instead. The compiler is just telling you in its own quaint way of this silliness.
On the other hand gibble is the name of a location that's capable of storing the location of any other value. (Well not exactly, but we won't get into the nits of memory alignment and C semantics.) So the assignment works fine.

Doing a direct struct read in C from preallocated memory failed

I'm assuming its a pointer issue again, but what I'm trying to do here is have a function search memory to see if an IP address exists, and if it doesn't then a random memory space is reserved for the IP address and zero is returned. the function takes an IP address as a string as the 1st parameter and the second parameter points to the struct. When the main() function is executed, result should equal 0 and result2 should equal 1, but instead, I get crashes, and I think it has to do with the way I'm assigning pointers?
In this fragment...
ip=(iprec*)p;
I'm trying to set the iprec structure passed into the function (and previously allocated by malloc), but I'm not sure where to add or remove stars from that statement.
Here is the rest of the code.
char *shma;
typedef struct{
unsigned char u;
unsigned char a[4];
unsigned int otherdata;
} iprec;
static int loadip(char* remoteip,iprec *ip){
char *p=shma;
int v=0;
char *ep;
unsigned char a[4];
sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);
int i,n;int sz=5000;
int szr=sizeof(iprec);
for (i=3;i<sz;i+=szr){
ip=(iprec*)p;
if (ip->u=='Y'){
for (n=0;n<=4;n++){
if (a[n]!=ip->a[n]){break;}
}
if (n >= 3){v=1;break;}
}else{
ep=p;
}
p+=szr;
}
if (v==0){
ip=(iprec*)ep;
for (n=0;n<=3;n++){
ip->a[n]=a[n];
}
}
return v;
}
int main(){
char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.
iprec *x=(iprec*)malloc(sizeof(iprec));
int result=loadip("127.0.0.1",x);
int result2=loadip("127.0.0.1",x);
}
Replace
sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);
With
sscanf(remoteip,"%d.%d.%d.%d",&a[0],&a[1],&a[2],&a[3]);
sccanf needs pointer type arguments.
shma should be global.
I haven't done a full analysis of your code, but here is a source of your crash. At the bottom is a resolution
Analysis
At the top of your snippet, you have
char *shma;
This is a file-scope (global) object called shma that has static duration storage. It gets initialized to 0 prior to main() executing.
Then, in main, you have:
int main(){
char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.
Here you declare a new object called shma. It has block scope (exists only within the context of main), with automatic storage. You assign to it a pointer from malloc(). Then you call loadip.
loadip has
char *p=shma;
Which declares a new object called p with block scope (exists in loadip) with automatic storage. You set it to shma. NOTE this is assigning the global shma, not the one in main, because the one in main only exists within main, and loadip is outside of main. The global shma was 0, so now p is also 0 (at least for your first loop).
Then, you do:
ip=(iprec*)p;
so, since p was 0, now ip is 0. In the next line:
if (ip->u=='Y'){
you are dereferencing ip to obtain member u. On most systems, this dereference will result in a segmentation fault (or similar memory access violation), because you have essentially dereferenced NULL (the 0 address).
Fix for this issue
Change
int main(){
char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.
into
int main(){
shma=(char*)malloc(5000); //alloc 5000 bytes for example.
This will result in main assigning to the global shma instead of creating a new local one.
Its a while since I've done C, but a few thoughts :
char *p=shma;
but shma has not yet been initialised - and consequently the "ip=(iprec*)p;" means ip will not be a valid value.
unsigned char a[4];
sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);
you need the address of the receiving variables (ie. &a[0], &a[1], ...).
Also, since '%d' will write 4 byte integers (the scanf doesn't know it's a char array), better to have "int a[4]"
ip=(iprec*)p;
But ip is an input parameter - so here you're overwriting (ie. throwing away) whatever value the user supplied in the second argument.
if (v==0){
ip=(iprec*)ep;
Even if v=0, it is still possible that ep has not been initialised (eg.if all ip->u == 'Y' but the a-arrays differ on the first or second values)

Confused about accessing struct members via a pointer

I'm new to C, and am confused by results I'm getting when referencing a member of a struct via a pointer. See the following code for an example. What's happening when I reference tst->number the first time? What fundamental thing am I missing here?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int number;
} Test;
Test* Test_New(Test t,int number) {
t.number = number;
return &t;
}
int main(int argc, char** argv) {
Test test;
Test *tst = Test_New(test,10);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
}
The output is:
Test.number = 10
Test.number = 4206602
Test.number = 4206602
When you pass test into your Test_New function, you are passing it by value and so a local copy is made on the stack for the function scope of your Test_New function. Since you return the address of the variable, once the function returns the stack is useless but you've returned a pointer to a struct on the old stack! So you can see that your first call returns the correct value since nothing has overwritten your stack value but the subsequent calls (which all use the stack) overwrite your value and give you erroneous results.
To do this correctly rewrite your Test_New function to take a pointer and pass the pointer to the struct into the function.
Test* Test_New(Test * t,int number) {
t->number = number;
return t;
}
int main(int argc, char ** argv) {
Test test;
Test * tst = Test_New(&test,10);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
}
Independent of struct, it is always incorrect to return the address of a local variable. It is usually also incorrect to put the address of a local variable into a global variable or to store it in an object allocated on the heap with malloc. Generally if you need to return a pointer to an object, you'll need either to get someone else to provide the pointer for you, or else you'll need to allocate space with malloc, which will return a pointer. In that case, part of the API for your function must specify who is responsible for calling free when the object is no longer needed.
You are returning the address of t as declared in the method Test_New, not the address of test that you passed into the method. That is, test is being passed by value and you should instead pass a pointer to it.
So, here is what happens when you call Test_New. A new Test struct named t is created and t.number is set to be equal to the value of test.number (which you had not initialized). Then you set t.number equal to the parameter number that you passed to the method, and then you return the address of t. But t is a local variable and goes out of scope as soon as the method ends. Thus, you are returning a pointer to data that no longer exists and that is why you are ending up with garbage.
Change the declaration of Test_New to
Test* Test_New(Test* t,int number) {
t->number = number;
return t;
}
and call it via
Test *tst = Test_New(&test,10);
and all will go as you are expecting.
Just to extend BlodBath's answer, think about what happens in memory when you do this.
As you enter your main routine, a new automatic Test struct is created -- on the stack, since it's auto. So your stack looks something like
| return address for main | will be used at bottom
| argc | copied onto stack from environment
| argv address | copied onto stack from environment
-> | test.number | created by definition Test test;
with -> indicating the stack pointer to the last used element of the stack.
Now you call Test_new(), and it updates the stack like this:
| return address for main | will be used at bottom
| argc | copied onto stack from environment
| argv address | copied onto stack from environment
| test.number | created by definition Test test;
| return addr for Test_new| used to return at bottom
| copy of test.number | copied into the stack because C ALWAYS uses call by value
-> | 10 | copied onto stack
When you return &t, which address are you getting? Answer: the address of the data ON THE STACK. BUT THEN you return, the stack pointer is decremented. When you call printf, those words on the stack are re-used, but your address is still poiting to them. It happens that what the number in that location in the stack, interpreted as an address, points to has the value 4206602, but that's pure chance; in fact, it was kind of bad luck, as good luck would have been something that caused a segmentation fault, letting you know something was actually broken.
The problem is that you are not passing a reference into Test_New, you are passing a value. Then, you're returning the memory location of the local variable. Consider this code which demonstrates your problem:
#include <stdio.h>
typedef struct {
} Test;
void print_pass_by_value_memory(Test t) {
printf("%p\n", &t);
}
int main(int argc, char** argv) {
Test test;
printf("%p\n", &test);
print_pass_by_value_memory(test);
return 0;
}
The output of this program on my machine is:
0xbfffe970
0xbfffe950
Test t declared in Test_New() is a local variable. You are trying to return the address of a local variable. As the local variable gets destroyed once the function exists, the memory will be freed meaning, the compiler is free to put some other value in the location where your local variable was kept.
In your program when you are trying to access the value the second time, the memory location might have got assigned to a different variable or process. Hence you are getting the wrong output.
A better option for you will be to pass the structure from main() by reference rather than by value.
You've passed the contents of test by value to Test_New. IOW a new copy of a Test structure has been allocated on the stack when you called Test_New. It is the address of this Test that you return from the function.
When you use tst->number the first time the value of 10 is retrieved because although that stack has be unwound no other use of that memory has been made. However as soon as that first printf has been called the stack memory is reused for whatever it needs, but tst is still pointing to that memory. Hence subsquent uses of tst->number retrieve whatever printf left there in that memory.
Use Test &t in the function signature instead.
You could do something like this to make it a little easier:
typedef struct test {
int number;
} test_t;
test_t * Test_New(int num)
{
struct test *ptr;
ptr = (void *) malloc(sizeof(struct test));
if (! ptr) {
printf("Out of memory!\n");
return (void *) NULL;
}
ptr->number = num;
return ptr;
}
void cleanup(test_t *ptr)
{
if (ptr)
free(ptr);
}
....
int main(void)
{
test_t *test, *test1, *test2;
test = Test_New(10);
test1 = Test_New(20);
test2 = Test_new(30);
printf(
"Test (number) = %d\n"
"Test1 (number) = %d\n"
"Test2 (number) = %d\n",
test->number, test1->number, test2->number);
....
cleanup(test1);
cleanup(test2);
cleanup(test3);
return 0;
}
... As you can see, its easy to allocate room for several completely different instances of test_t, for instance if you need to save the existing state of one so you can revert later .. or for whatever reason.
Unless, of course there is some reason why you must keep it local .. but I really can't think of one.

Resources