jdm5548@diamond.tamu.edu (James Darrell McCauley) (08/07/90)
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) Could some kind guru point out the error? Thank you very much. --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - James Darrell McCauley jdm5548@diamond.tamu.edu Dept of Ag. Engineering (409) 845-6484 Texas A&M University, College Station, Texas 77843-2117, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
jdm5548@diamond.tamu.edu (James Darrell McCauley) (08/07/90)
I forgot to add this, in case the problem is not just my own ignorance: SUN 4.0.3 using /bin/cc --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - James Darrell McCauley jdm5548@diamond.tamu.edu Dept of Ag. Engineering (409) 845-6484 Texas A&M University, College Station, Texas 77843-2117, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
burley@world.std.com (James C Burley) (08/07/90)
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]);
...
}
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!
James Craig Burley, Software Craftsperson burley@world.std.com
diamond@tkou02.enet.dec.com (diamond@tkovoa) (08/07/90)
In article <7206@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes: >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?) -- Norman Diamond, Nihon DEC diamond@tkou02.enet.dec.com This is me speaking. If you want to hear the company speak, you need DECtalk.
pierre@rhi.hi.is (Kjartan Pierre Emilsson) (08/07/90)
From article <7206@helios.TAMU.EDU>, by jdm5548@diamond.tamu.edu (James Darrell McCauley): > 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... > } > which produces the following output: > ... some output ... > 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 Iceland email: pierre@krafla.rhi.hi.is
richard@aiai.ed.ac.uk (Richard Tobin) (08/07/90)
In article <7206@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes: > 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 -- Richard Tobin, JANET: R.Tobin@uk.ac.ed AI Applications Institute, ARPA: R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin
ping@cubmol.bio.columbia.edu (Shiping Zhang) (08/07/90)
In article <7206@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes: >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
mcdaniel@adi.com (Tim McDaniel) (08/07/90)
diamond@tkou02.enet.dec.com (diamond@tkovoa) writes: In article <7206@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes: >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 Internet: mcdaniel@adi.com UUCP: {uunet,sharkey}!amara!mcdaniel
mcdaniel@adi.com (Tim McDaniel) (08/07/90)
jdm5548@diamond.tamu.edu (James Darrell McCauley) asked about setting
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
Internet: mcdaniel@adi.com UUCP: {uunet,sharkey}!amara!mcdaniel
jrbd@craycos.com (James Davies) (08/08/90)
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?
george@hls0.hls.oz (George Turczynski) (08/08/90)
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]); } 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 ***/ 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... George P. J. Turczynski. | ACSnet: george@highland.oz | 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...
ptb@ittc.wec.com (Pat Broderick) (08/08/90)
In article <7206@helios.TAMU.EDU>, jdm5548@diamond.tamu.edu (James Darrell McCauley) writes: > 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; } In main() your call would then look like: a = inita(a,b); Hope this helps -- Patrick T. Broderick |ptb@ittc.wec.com | |uunet!ittc!ptb | |(412)733-6265 |
diamond@tkou02.enet.dec.com (diamond@tkovoa) (08/09/90)
In article <7206@helios.TAMU.EDU> jdm5548@diamond.tamu.edu (James Darrell McCauley) writes: >>>main() { >>> int *a,*b; There must have been some static (:-) affecting my mind when I replied: >>Initially, a and b are NULL pointers (do not point to anything usable). (But I got the rest of it right.) In article <MCDANIEL.90Aug7105551@dolphin.adi.com> mcdaniel@adi.com (Tim McDaniel) writes: >Not NULL (which is a definite value), undefined. Yes, thank you. (And he didn't even flame me.) -- Norman Diamond, Nihon DEC diamond@tkou02.enet.dec.com This is me speaking. If you want to hear the company speak, you need DECtalk.