Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
| Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
07-17-2004, 02:02 AM
|
#1
|
|
Member
Registered: Aug 2003
Location: Dallas,TX
Distribution: Ubuntu Server, Slackware, Red Hat 6.1
Posts: 241
Rep:
|
a question about array pointers in C
Lately I've been following a tutorial on the C program language. Most of its been a breeze but I'm stuck on this one part about pointers dealing with arrays. Here's the code:
Code:
int add_array(int array[], int size)
{
int i;
int total = 0;
for(i = 0; i < size; i++)
total += array[i];
return(total);
}
I understand the everything except the function declaration, int add_array(int array[], int size). I just don't understand the point of "int array[]" other than it has something to do with a pointer. When I create a main function and call "add_array(10,10)" I get a warning saying "passing arg 1 of 'add_array' makes pointer from integer without cast". (and a segment fault when the program is executed)What is a cast and what exactly are you supposed to put in the first argument slot?
|
|
|
|
07-17-2004, 02:26 AM
|
#2
|
|
Member
Registered: Jul 2004
Location: Rio de Janeiro - Brazil
Distribution: Conectiva 10 - Conectiva 8 - Slackware 9 - starting with LFS
Posts: 519
Rep:
|
Hi veritas,
Your function wants to receive an array pointer as the first argument and you are giving it an integer. In the main function you have to declare an array then initialize it and then pass it to the function.
Code:
add_array(xyz, 10);
The compile warning told you you are passing an integer "10" in place of an array pointer. So the function tried to use the number 10 as the memory address of your array. As it was out of bounds, you got the seg fault in the execution.
Remember, c will always try to follow your desires or die trying to do it. I always look for every warning and I remove it because, in a "warning forest" we cannot discover the bad ones.
I hope this helps.
|
|
|
|
07-17-2004, 02:53 AM
|
#3
|
|
Member
Registered: Apr 2004
Location: berkeley, ca
Distribution: slk10, winxp
Posts: 313
Rep:
|
a cast is a way to tell the compiler to interpret something as a different type than it would normally interpret, and to tell it you know exactly what you are doing.
in your case, 10 is normally an integer. that's why the compiler complains when you give add_array an integer when add_array expects an integer pointer. now, if you want to get rid of the warning, you can do add_array((integer *)10, 10), which tells the compiler that you know exactly that the address 10 points to an integer. of course, you will still get the seg fault run time error because the address 10 doesn't belong to you.
|
|
|
|
07-17-2004, 01:20 PM
|
#4
|
|
Senior Member
Registered: Jan 2004
Location: Oregon, USA
Distribution: Slackware
Posts: 1,246
Rep:
|
If somehow you knew that 10 was a valid pointer, you'd be able to cast 10 to a pointer to avoid the warning. However, you'd still get the segfault because you'll never see 10 be a valid pointer. To get rid of the warning you'd do add_array((int *)10, 10);
|
|
|
|
07-17-2004, 02:45 PM
|
#5
|
|
Member
Registered: Aug 2003
Location: Dallas,TX
Distribution: Ubuntu Server, Slackware, Red Hat 6.1
Posts: 241
Original Poster
Rep:
|
Quote:
Originally posted by osvaldomarques
|
Ah ok. That helps a lot, mainly because I didn't know I was supposed to declare that in the main function. The tutorial just gave me the add_array function without the main function. Thanks for all of the replys. Now this is making sense.
|
|
|
|
07-17-2004, 02:55 PM
|
#6
|
|
Member
Registered: Aug 2002
Distribution: Debian
Posts: 540
Rep:
|
int add_array(int *array, int size)
is basiaclly the same thing. However, it is faster. You see, when the function add_array gets called, the variables array and size are created (on the stack?) and the values that belong to them are assigned to them. So when you have an array, say of 100, then 100 values have to get assigned at each function call! (actually +1 for size). But using pointers, you only ever need one value assigned (+1 for size) because a pointer only holds the value of the start of an array, or the address of an array.
So you have a memory chunk in your computer, like so:
1...2...10 n
---------------------------------------
And when you typecast 10 to a address your function will start assigning values from memory startying at 10. Just put it this way, you'll NEVER see a memory address of 10! So basically, your program is trying to access and/or give itself memory, or maybe something else, that doesn't belong to it. Here is the difference between a intager variable, and an intager array (V is where the value is in memory):
Int Var: (memory) V-----------------
Int Array: (memory) VVVVVVVVVV----
So this would be perfectly valid:
int var=1;
add_array((int *)&var, 1);
However, if you said:
add_array((int *)&var, 2);
You would cause a SEGV because you are trying to access memory beyond the address location where var is stored in memory.
Sum:
int add_array(int array[], int size)
this is the same as the following except that it is way slower and take way more memory:
int add_array(int *array, int size)
Sorry I don't write to well, I hope you understand and get the picture.
|
|
|
|
07-17-2004, 03:13 PM
|
#7
|
|
Member
Registered: Aug 2003
Location: Dallas,TX
Distribution: Ubuntu Server, Slackware, Red Hat 6.1
Posts: 241
Original Poster
Rep:
|
Quote:
int add_array(int array[], int size)
this is the same as the following except that it is way slower and take way more memory:
int add_array(int *array, int size)
|
Thanks. I'll definitely keep that in mind. All though some of the stuff was a bit over my head, but I get the basic picture.
|
|
|
|
07-17-2004, 05:06 PM
|
#8
|
|
Member
Registered: Jul 2004
Location: Rio de Janeiro - Brazil
Distribution: Conectiva 10 - Conectiva 8 - Slackware 9 - starting with LFS
Posts: 519
Rep:
|
Hi veritas,
When there is doubt, the computer always have reason. So, I wrote a little piece of c to check the assembler code produced. Intentionally I left one of the warnings which make the "forest" and its easy to remove. The c source file has 3 identical functions, one with pointer declaration, one with an empty array and one with a full array declaration. All the 3 functions are called from main. I compiled it to generate assembler source instead of generate final code. Here is the test.c source
Code:
int add_full_array(int arr[10], int size)
{
int ret
;
ret = *arr * size;
return(ret);
}
int add_array(int arr[], int size)
{
int ret
;
ret = *arr * size;
return(ret);
}
int add_pointer(int *ptr, int size)
{
int ret
;
ret = *ptr * size;
return(ret);
}
void main(void)
{
int tst[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
;
int var
;
var = 1;
add_full_array(tst, 10);
var = 2;
add_array(tst, 10);
var = 3;
add_pointer(tst, 10);
var = 4;
}
Here is the resulting test.asm source
Code:
.file "test.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl add_full_array
.type add_full_array,@function
add_full_array:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movl 8(%ebp),%eax
movl (%eax),%edx
imull 12(%ebp),%edx
movl %edx,-4(%ebp)
movl -4(%ebp),%edx
movl %edx,%eax
jmp .L2
.p2align 4,,7
.L2:
leave
ret
.Lfe1:
.size add_full_array,.Lfe1-add_full_array
.align 4
.globl add_array
.type add_array,@function
add_array:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movl 8(%ebp),%eax
movl (%eax),%edx
imull 12(%ebp),%edx
movl %edx,-4(%ebp)
movl -4(%ebp),%edx
movl %edx,%eax
jmp .L3
.p2align 4,,7
.L3:
leave
ret
.Lfe2:
.size add_array,.Lfe2-add_array
.align 4
.globl add_pointer
.type add_pointer,@function
add_pointer:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movl 8(%ebp),%eax
movl (%eax),%edx
imull 12(%ebp),%edx
movl %edx,-4(%ebp)
movl -4(%ebp),%edx
movl %edx,%eax
jmp .L4
.p2align 4,,7
.L4:
leave
ret
.Lfe3:
.size add_pointer,.Lfe3-add_pointer
.section .rodata
.align 4
.LC0:
.long 0
.long 1
.long 2
.long 3
.long 4
.long 5
.long 6
.long 7
.long 8
.long 9
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
subl $64,%esp
pushl %edi
pushl %esi
leal -40(%ebp),%edi # get tst array local address
movl $.LC0,%esi # get address of initializer
cld # clear direction
movl $10,%ecx # set counter to 10 repetitions
rep # start repeat
movsl # move string long
movl $1,-44(%ebp) # var = 1;
addl $-8,%esp
pushl $10
leal -40(%ebp),%eax
pushl %eax
call add_full_array
addl $16,%esp
movl $2,-44(%ebp) # var = 2;
addl $-8,%esp
pushl $10
leal -40(%ebp),%eax
pushl %eax
call add_array
addl $16,%esp
movl $3,-44(%ebp) # var = 3;
addl $-8,%esp
pushl $10
leal -40(%ebp),%eax
pushl %eax
call add_pointer
addl $16,%esp
movl $4,-44(%ebp) # var = 4;
.L5:
leal -72(%ebp),%esp
popl %esi
popl %edi
leave
ret
.Lfe4:
.size main,.Lfe4-main
.ident "GCC: (GNU) 2.95.3 20010315 (release)"
In the c, on the main function, I introduced a variable called "var", and before each function call I initialized it to ease the tracking of the start and end of the function calls into the resulting assembler. In the resulting assembler, I did some notes after '#' in the main function, showing the array initialization and marking where the var variable is initialized. As we can see, the code of the 3 functions are completely identical and the assembler instructions to call each of the functions are also the same.
That's the part of my life I most hate. When I disagree with the computer, it is always right! By the way, the command used to compile it is
Code:
gcc -S -o test.asm test.c
|
|
|
|
07-17-2004, 05:32 PM
|
#9
|
|
Senior Member
Registered: Dec 2002
Location: England
Distribution: Used to use Mandrake/Mandriva
Posts: 2,794
Rep: 
|
Thanks a bunch osvaldomarques, I was thinking the others were slightly incorrect and that reply really explains it all.
Just wanted to check veritas, you were reading this page right?
|
|
|
|
07-17-2004, 05:45 PM
|
#10
|
|
Member
Registered: Apr 2004
Location: berkeley, ca
Distribution: slk10, winxp
Posts: 313
Rep:
|
phew, The_Nerd scared the hell out of me because I haven't used C in a while and what The_Nerd said was completely different than what I remembered. I thought my C was so rusty. but thanks to osvaldomarques, i didn't have to verify the situation.
|
|
|
|
07-17-2004, 07:26 PM
|
#11
|
|
Member
Registered: Aug 2003
Location: Dallas,TX
Distribution: Ubuntu Server, Slackware, Red Hat 6.1
Posts: 241
Original Poster
Rep:
|
Quote:
|
Just wanted to check veritas, you were reading this page right?
|
Yep, thats the one. But now I'm reading a pretty thorough pointers tutorial located here:
http://pweb.netcom.com/~tjensen/ptr/pointers.htm
edit: I will continue with the other one when i get a complete grasp on pointers dealing with the most common data types. I wonder why the strath.ac.uk website went into pointers so early (since they deal with memory locations and other non newbie friendly things)? There is probably another way to demonstrate a while loop.
Last edited by veritas; 07-17-2004 at 07:32 PM.
|
|
|
|
07-18-2004, 01:24 PM
|
#12
|
|
Member
Registered: Nov 2001
Location: London, England
Distribution: Gentoo, FreeBSD
Posts: 590
Rep:
|
Quote:
int add_array(int *array, int size)
is basiaclly the same thing. However, it is faster. You see, when the function add_array gets called, the variables array and size are created (on the stack?) and the values that belong to them are assigned to them. So when you have an array, say of 100, then 100 values have to get assigned at each function call! (actually +1 for size). But using pointers, you only ever need one value assigned (+1 for size) because a pointer only holds the value of the start of an array, or the address of an array.
|
No, array arguments to functions are passed as pointers; they aren't copied. If you use int array[] instead of int *array as the argument, the only difference is that you could modify the 'array' variable. In general:
int *foo;
and
int foo[];
are exactly the same except for the fact that in the first one, 'foo' is a variable and can have its value changed, whereas in the second, 'foo' is not a variable and its value is fixed.
Alex
|
|
|
|
07-18-2004, 06:31 PM
|
#13
|
|
Member
Registered: Jul 2004
Location: Rio de Janeiro - Brazil
Distribution: Conectiva 10 - Conectiva 8 - Slackware 9 - starting with LFS
Posts: 519
Rep:
|
Hi gentlemen,
Sorry, but gcc disagree with us. I said I hate this, but, I did alter the previous c source to produce some result
Code:
#include <stdio.h>
int add_full_array(int arr[10], int size)
{
int ret
;
for (ret = 0; size; arr++, size--)
{
ret += *arr * size;
// printf("Processing: ret = %d * %d\n", *arr, size);
}
printf("add full array: %d\n", ret);
return(ret);
}
int add_array(int arr[], int size)
{
int ret
;
for (ret = 0; size; arr++, size--)
{
ret += *arr * size;
// printf("Processing: ret = %d * %d\n", *arr, size);
}
printf("add array: %d\n", ret);
return(ret);
}
int add_pointer(int *ptr, int size)
{
int ret
;
for (ret = 0; size; ptr++, size--)
{
ret += *ptr * size;
// printf("Processing: ret = %d * %d\n", *ptr, size);
}
printf("add pointer: %d\n", ret);
return(ret);
}
void main(void)
{
int tst[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
;
int var
;
var = 1;
add_full_array(tst, 10);
var = 2;
add_array(tst, 10);
var = 3;
add_pointer(tst, 10);
var = 4;
}
and compiled it with After run it (./test), the result is
Code:
Opiii:~/teste# ./test
add full array: 165
add array: 165
add pointer: 165
|
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 10:41 PM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|