SIMPLE malloc & pointer question
Author |
Message |
James Darrell McCaul #1 / 13
|
 SIMPLE malloc & pointer question
I have the following code: ---cut here #include<stdio.h> #include<malloc.h> main() { int *a,*b; b=(int *)malloc( (unsigned) 4*sizeof(int)); b[2]=5; printf("main(): b[2]=%d\n",b[2]); inita(a,b); printf("main(): a[2]=%d\n",a[2]); Quote: }
inita (a,b) int a[],b[]; { a=(int *)malloc( (unsigned) 4*sizeof(int)); a[2]=3; printf("inita(): a[2]=%d\n",a[2]); printf("inita(): b[2]=%d\n",b[2]); Quote: }
---cut here which produces the following output: main(): b[2]=5 inita(): a[2]=3 inita(): b[2]=5 Segmentation fault (core dumped) Could some kind guru point out the error? Thank you very much. --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dept of Ag. Engineering (409) 845-6484 Texas A&M University, College Station, Texas 77843-2117, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
Sat, 23 Jan 1993 10:08:58 GMT |
|
 |
James C Burl #2 / 13
|
 SIMPLE malloc & pointer question
I think the problem is that you're expecting inita to return the pointer it allocated for <a>, but that doesn't happen. main passes to inita the current values for pointers <a> and <b>. inita immediately overwrites its own LOCAL COPY (as always in C) with the address of allocated memory, then writes through that address in "a[2]=3;". Then it returns to main. Now, main still has the old (uninitialized) value of <a>, so when it tries to read through that address, anything (including a segment violation) can happen. Even a random number getting output. Meanwhile, the pointer to inita's heap-allocated area has been lost forever, since it was kept only in <a>, which is now popped off the stack (ok, it's probably still there somewhere, but not after the next function call...). Try something like this instead: inita(&a,b); /* Call inita, a is input/output arg, b is input only. */ ... inita(a,b) int *a[]; int b[]; { *a = (int *) malloc... *a[2] = 3; printf(...*a[2]); ... Quote: }
I might have the precedence wrong -- too zonked to be sure without further playing -- but I hope you get the idea. Here, inita is using indirection through a local copy of a pointer to main's (pointer to) <a>, so it can modify main's copy of <a>. It still does basically the same thing except that after returning, the pointer to the heap-allocated area is still present in main's copy of <a>, and thus your program would work. Unless you need to say "(*a)[2] = 3;" and so on, in which case excuse my sloppiness, please!
|
Sat, 23 Jan 1993 14:59:27 GMT |
|
 |
James Darrell McCaul #3 / 13
|
 SIMPLE malloc & pointer question
I forgot to add this, in case the problem is not just my own ignorance: SUN 4.0.3 using /bin/cc --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dept of Ag. Engineering (409) 845-6484 Texas A&M University, College Station, Texas 77843-2117, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
Sat, 23 Jan 1993 10:22:05 GMT |
|
 |
diamon #4 / 13
|
 SIMPLE malloc & pointer question
>main() { > int *a,*b; Initially, a and b are NULL pointers (do not point to anything usable). > b=(int *)malloc( (unsigned) 4*sizeof(int)); Now b points to some storage that the program can use, and a is still null. > inita(a,b); Now b still points to some storage that the program can use, and a is still null. The null pointer in a was copied to inita's first argument. The useful pointer in b was copied to initb's second argument. Nothing was copied back. C function calls are call-by-value, not call-by-value-return, not call-by-reference. >} >inita (a,b) int a[],b[]; { > a=(int *)malloc( (unsigned) 4*sizeof(int)); This changes one of inita's variables from null to a useful pointer. Unfortunately, no one gives the useful pointer back to main. >} (Note to the FAQ list maintainer: Does the FAQ list mention call-by-value?) --
This is me speaking. If you want to hear the company speak, you need DECtalk.
|
Sat, 23 Jan 1993 15:55:48 GMT |
|
 |
Kjartan Pierre Emilss #5 / 13
|
 SIMPLE malloc & pointer question
Quote: > I have the following code: > main() > { > int *a,*b; > b=(int *)malloc( (unsigned) 4*sizeof(int)); > b[2]=5; > printf("main(): b[2]=%d\n",b[2]); > inita(a,b); > printf("main(): a[2]=%d\n",a[2]); > } > inita (a,b) > int a[],b[]; > { > a=(int *)malloc( (unsigned) 4*sizeof(int));
...stuff deleted... Quote: > } > which produces the following output:
... some output ... Quote: > Segmentation fault (core dumped)
Arguments to function in C are passed by value, which means that a function cannot alter the content of variables passed to it, but to do so you must pass the *adress* of the variable you want to change (the pointer to the memory location of the data you want to change). A correct version of inita() would thus be: inita(a,b) int **a,*b; { *a = (int *)malloc(4*sizeof(int)); (*a)[2] = 1.0; } Which should be called as inita(&a,b). ------------------------------------------------------------------------------- Kjartan Pierre Emilsson Science Institute of The University of Iceland Dunhaga 3 Reykjavik
|
Sat, 23 Jan 1993 18:07:03 GMT |
|
 |
Richard Tob #6 / 13
|
 SIMPLE malloc & pointer question
Quote: > inita(a,b); > printf("main(): a[2]=%d\n",a[2]); >inita (a,b) >int a[],b[]; >{ > a=(int *)malloc( (unsigned) 4*sizeof(int)); > a[2]=3;
Arguments in C are passed by value, not reference. inita() gets a copy of main()'s variable "a", so when inita() returns the value in main() is unchanged. If you want to modify a variable in the parent procedure, you should pass a pointer to it: inita(&a,b); and declare the argument appropriately: int **a; /* a is a pointer to a pointer to integers */ and assign to what the argument points to, not the argument itself (*a)=(int *)malloc( (unsigned) 4*sizeof(int)); (*a)[2]=3; -- Richard --
Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin
|
Sat, 23 Jan 1993 22:22:03 GMT |
|
 |
James Davi #7 / 13
|
 SIMPLE malloc & pointer question
Just to beat this into the ground a bit further (like most simple problems posted to the net, it's already halfway to the earth's core by now...), the first thing to do when you have questions about a particular program should be to run it through lint. In this case, lint says: $ lint xxx.c xxx.c(11): warning: a may be used before set printf returns value which is always ignored The first warning should be a strong clue as to what is wrong... Is lint mentioned in the FAQ list?
|
Sun, 24 Jan 1993 05:37:25 GMT |
|
 |
George Turczyns #8 / 13
|
 SIMPLE malloc & pointer question
Well, for starters, try this code instead: /*** Cut here ***/ #include<stdio.h> #include<malloc.h> main() { int *a,*b; b=(int *)malloc( (unsigned) 4*sizeof(int)); b[2]=5; printf("main(): b[2]=%d\n",b[2]); inita(&a,b); /* <<==== */ printf("main(): a[2]=%d\n",a[2]); Quote: }
inita (a,b) int *a[],b[]; /* <<==== */ { *a= (int *)malloc( (unsigned) 4*sizeof(int)); /* <<==== */ (*a)[2]=3; /* <<==== */ printf("inita(): a[2]=%d\n",(*a)[2]); /* <<==== */ printf("inita(): b[2]=%d\n",b[2]); Quote: }
/*** Cut here ***/ It produces the output: "scratch: a.out main(): b[2]=5 inita(): a[2]=3 inita(): b[2]=5 main(): a[2]=3 scratch: " Which is probably what you expected of your code ? The reason it failed is because you passed the value of (int *)a to inita(), and not its address. The value was of course NULL, but was then assigned a value by your call to malloc(), and this is perfectly valid. That is why a[2] was meaningful in inita(). The problem is that you altered a stack variable `a' in inita() and not the stack variable `a' in main(), which is what you thought you did. When you got back into main(), `a' was still NULL, and voila, `a[2]' will cause a SIGSEGV to be sent to the process ! I hope you can follow my altered version of your code. There are changes where you see the "/* <<==== */" symbol. The `(*a)' must be used as the `[]' binds tighter than the `*'. If you leave the `()' out you will still get a segmentation violation, but for a different reason. I hope this has answered any questions you had. Have a nice day...
| Phone: 61 48 683490 Computer Systems Engineer. | Fax: 61 48 683474 |---------------------- Highland Logic Pty. Ltd. | I can't speak for the Suite 1, 348-354 Argyle Street | company, I can barely Moss Vale. NSW. 2577 Australia | speak for myself...
|
Sun, 24 Jan 1993 07:27:43 GMT |
|
 |
Tim McDani #9 / 13
|
 SIMPLE malloc & pointer question
>main() { > int *a,*b; Initially, a and b are NULL pointers (do not point to anything usable). K&R2, sec. A8.7, page 219: The initial value of an automatic object not explicitly initialized is undefined. Not NULL (which is a definite value), undefined. "a == NULL" need not be true; in fact, it is permitted to cause a fatal fault. In the referenced article, substitute "undefined" for "null". -- "I'm not a nerd -- I'm 'socially challenged'." Tim McDaniel
|
Sat, 23 Jan 1993 22:55:51 GMT |
|
 |
Tim McDani #10 / 13
|
 SIMPLE malloc & pointer question
a function argument. The answer has been given elsewhere (argument values are local; changes are not passed back to the parent). I just have small style quibbles. main() { ... inita(a,b); ... } inita (a,b) int a[],b[]; { a=(int *)malloc( (unsigned) 4*sizeof(int)); ... } I have style rules to avoid confusion in the reader and to avoid bugs: * I declare before use, even if the compiler seems to let me get away with it. inita was not a problem only because it returns type int. * I don't try to lie to the compiler. If a function doesn't return a value, I define it "void". If a function is taking a pointer as argument, I say so, because you can't pass arrays as arguments in C. Inita falls under both these points. So I would have written void inita (a,b) int *a, *b; { ... } main () { ... } -- "I'm not a nerd -- I'm 'socially challenged'." Tim McDaniel
|
Sat, 23 Jan 1993 23:18:56 GMT |
|
 |
Shiping Zha #11 / 13
|
 SIMPLE malloc & pointer question
Quote: >I have the following code: >---cut here >#include<stdio.h> >#include<malloc.h> >main() >{ > int *a,*b; > b=(int *)malloc( (unsigned) 4*sizeof(int)); > b[2]=5; > printf("main(): b[2]=%d\n",b[2]); > inita(a,b); > printf("main(): a[2]=%d\n",a[2]); >} >inita (a,b) >int a[],b[]; >{ > a=(int *)malloc( (unsigned) 4*sizeof(int)); > a[2]=3; > printf("inita(): a[2]=%d\n",a[2]); > printf("inita(): b[2]=%d\n",b[2]); >} >---cut here >which produces the following output: >main(): b[2]=5 >inita(): a[2]=3 >inita(): b[2]=5 >Segmentation fault (core dumped)
Remember that in C, function arguments are passed by value and their original values are not changed no matter what operation has been applied to them in the called functions. So in inita(), a is assigned a value (the address of some memery location), but the value is not saved when return from that function and a points to nowhere or anywhere. The simplest way to solve this problem in this case is just to move the first statement of inita() to somewhere in the main function before inita is called. -ping
|
Sat, 23 Jan 1993 22:24:53 GMT |
|
 |
Pat Broderi #12 / 13
|
 SIMPLE malloc & pointer question
Quote: > I have the following code: > ---cut here > #include<stdio.h> > #include<malloc.h> > main() > { > int *a,*b; > ... > inita(a,b); > printf("main(): a[2]=%d\n",a[2]); > } > [stuff deleted]
The problem with the code is that "a", is initialized in function inita(), its value is never known in main(). When you try to print a[2] you get the SEGV. Several solutions are possible, you might try either of the following: (1) perform the malloc() for a in main() (2) define inita() as a function returning a pointer, e.g. int *inita (a,b) int a[],b[]; { a=(int *)malloc( (unsigned) 4*sizeof(int)); a[2]=3; printf("inita(): a[2]=%d\n",a[2]); printf("inita(): b[2]=%d\n",b[2]); return a; Quote: }
In main() your call would then look like: a = inita(a,b); Hope this helps --
|uunet!ittc!ptb | |(412)733-6265 |
|
Sun, 24 Jan 1993 23:04:16 GMT |
|
 |
diamon #13 / 13
|
 SIMPLE malloc & pointer question
Quote: >>>main() { >>> int *a,*b;
There must have been some static (:-) affecting my mind when I replied: Quote: >>Initially, a and b are NULL pointers (do not point to anything usable).
(But I got the rest of it right.) Quote:
>Not NULL (which is a definite value), undefined.
Yes, thank you. (And he didn't even flame me.) --
This is me speaking. If you want to hear the company speak, you need DECtalk.
|
Mon, 25 Jan 1993 11:56:06 GMT |
|
|
|