• C

simple on arrays in Linux C

main()
{  
     char tmp[10] ;
     tmp[21] = 'k' ;
}
above code will not produce errors (forget the include and all stuff)
but
this following will produce a segmentation fault...why
char *tmp ;
*(tmp+100) = 'k' ;

LVL 10
kiranghagAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

newmangCommented:
In the first case you are allocating an array of 10 bytes called tmp. You are then copying the value 'k' to the byte that is 22 bytes (array numbering starts at 0) from the address of first element in tmp. This is perfectly legal in C as the language has no bounds checking for arrays. By doing this you are writing over another area of memory which may contain anthing, another variable, some code, the stack or whatever depending on the layout of your binary. The chances are that the area that you are over-writing is within your own executable and therefore although it may (will) cause unpredictable errors in the program operation the operating system will not warn you that you have done something dumb.

In the second case you declare a pointer of type character and name it tmp. This only allocates a pointer variable not an area to which it points. In most cases uninitialised pointers are set to 0x00 and therefore in your next step you are attempting to write to an address that you do not have rights to write to, hence the core dump.

You should be doing

char * tmp;
tmp=(char *)malloc(some_size);
do_something_with_the_memory.......
free(tmp);


Cheers - Gavin
0
newmangCommented:
Sorry about the typos - new keyboard!
0
kiranghagAuthor Commented:
if i say
char *tmp = 10 ; //initialization

and then *tmp = 'k' ;
it still gives fault.
my point is whnever i use a pointer to do some operation like this it faults. why/

dear friend, this i am doing to know how its done internally. i am otherwise very clear abt the pointers and such stuff.
0
Powerful Yet Easy-to-Use Network Monitoring

Identify excessive bandwidth utilization or unexpected application traffic with SolarWinds Bandwidth Analyzer Pack.

tzxie2000Commented:
if you set the tmp to 10,it still in an undefined area.
the most probability is that it point to the syste area or some place not under the memory area about your program.
this will cause the system error.
if you try the code before:

main()
{
char * a;
char b[100];
a=b+200;
*a='\0';
}

it is almost like the first code your write and it will not cause a segment fault at all.

as you set the point a to b+200,the pointer a is set to the memroy area where your program can control or being malloced by system for your program.so it would not cause a segment fault.but it will destroy the data.
it is one of the most posible error the programmer maked and it is hard to be found as the error will display always at the point as you want to use the data after it.
look at it

main()
{
 char a[10];
 char b;

 memset(a,0,100);
 printf("%c",b);
}

the b will be printf out by 0,and if b is an control var,it will be more difficult to find the error
0
ecwCommented:
Read a book on OS design, specifically the chapters on memory management.

If the address you are accessing is not mapped into your address space, a hardware exception is generated, the cpu jumps into some sort of supervisory mode, and starts executing the trap handler dedicated to that exception.  This is part of the OS, the OS says uh-oh you've been naughty, and uses whatever mechanism it has to terminate the program, on UNIX, a segmentation violation.
0
newmangCommented:
kiranqhaq

The problem with your statement

char *tmp = 10 ; //initialization

is that you are setting a pointer to point to absolute address 10 and this is not an area of memory available to your program - hence the OS will protect itself by seg faulting
0
kiranghagAuthor Commented:
newmang>
do u mean to say setting *tmp = 10 maps the address into IVT? then u are wrong, it maps to 10 in the data segment.

i am aware that when I cross array bounds, segfault may or may not occur. ut whenever I try to do it with pointers (not arrays) i get segfault. and i want to know why that happens. does the compiler has any special treatment for arrays and pointers
0
newmangCommented:
kiranqhaq

I did not say that it mapped into the IVT, it does map into to address 10 in the text segment but the low end of this segment is marked read-only as it contains code and therefore an attempt to write to it causes the segfault.

Cheers - Gavin
0
newmangCommented:
To answer your second point, no the compilerdoes not have any "special" treatment for arrays and pointers. With C, as you have found out, you are on your own to a large extent.

Cheers - Gavin
0
ShivshankarCommented:
When you have declared local arrays, most of the compilers, put them in the stack(except for those compilers which treat arrays as static). So... what you're doing is just modifying the contents of stack which are not referenced to until your program terminates. Write a very big program with all stuff and in every place mis-use/cross the boundary line and you'll end up with a system crash. If you don't, give your compiler a pat at its back. You're simply lucky!!!

Nothing else can define this phenomenon.
0
kiranghagAuthor Commented:
newmang>>> i dont think any compilers puts code in the data segment (what is text segment? is it data segment for u? ) . why it should do that?
0
newmangCommented:
kiranqhaq

my terminology and/or explanation may not have been clear enough.. let me revisit it..

In the address space of the process the data would be laid out like this

LOW ADDRESS
text segment
data segment
stack segment
HIGH ADDRESS

The text segment contains code and read-only data and is read only. the data segment contains initialised and uninitialised data (static variables). The size of this area can be changed with the brk() function. The stack segment is used to hold automaitic variables.

When you dereference your pointer without an intervening malloc it will "point" into an address in the low memory text segment and cause the core.

Hope this make it clearer.

Cheers - Gavin
0
kiranghagAuthor Commented:
your notions of read only segments seems to be from protected mode world. they do not well apply to low level C world
0
newmangCommented:
kiranqhaq

Its got nothing to do with protected mode as far as I can see, its the standard binary layout for a Unix (Solaris, Linux, AIX) process in memory irrespective of the source language (it's a binary remember).

Cheers - Gavin
0
obgCommented:
Lots of comments... Hope that you can forgive if this has been said already.

Linux uses memory protection and address 10 is simply part of the protected memory area, while a couple of bytes up in the stack is most likely not protected (as long as you don't step to high up). Be careful though, cause you might overwrite some return addresses. The same goes for global variables, which will end up in an unprotected data area in memory.
0
SlordakCommented:
The discussion here seems to have already completely exhausted this issue, but if there is still any confusion...

This seems to be a classical error of declaring a pointer and treating the pointer as if it itself had memory allocated for storing a value, i.e.:

char tmp1;
vs.
char *tmp2;

In the first case, the compiler allocates (stack) storage for a single character variable.  In the second case, the compiler allocates space for a character pointer.  This pointer, of course, can point to various memory locations, but declaring a pointer doesn't automatically grant one the storage for a variable of this type (declaring a char pointer does not create a character to which it points; you can certainly make it point to a valid character variable, though).  Example with above declarations:

tmp1 = 'a';   /* Good. */
tmp2 = (some random address);
*tmp2 = 'b';  /* Almost certainly going to break! */

If you want actual value storage, declare a non-pointer variable (or an array of such variables), or else use malloc().
0
kiranghagAuthor Commented:
nope, i am satisfied...
0
kiranghagAuthor Commented:
nope, i am not satisfied...
0
newmangCommented:
Now I'm confused...are you satisfied or are you not satisfied (if not, why not)?
0
kiranghagAuthor Commented:
i am not,
cause the folks are explaining me how to use pointers and not how going abt solving my doubt. though i am not an expert on pointers and c , i have worked quite a bit on it.
please read the problem again

HTH
Kiran
http://kiran7.freeservers.com

0
newmangCommented:
Now I'm confused...are you satisfied or are you not satisfied (if not, why not)?
0
newmangCommented:
Kiran

Refer to my first post. This explained what you were seeing. Subsequent postings have fleshed this out and/or explained the same result in different terms.

In summary..

Your first code snippet writes beyond the bounds of pre-allocated memory within the writeable area of your process in memory - the result, as I said before, is that the operation succeeds BUT subsequent problems may occure depending on what was in the area you over-wrote.

In your second code snippet you attempt to use an uninitialised pointer to address memory to be written to. Because you have not allocated memory for the pointer to point to and thereby place a valid memory address in that pointer it still contains 0 and therefore you are attempting to write to memory in an area of your process image which is marked read-only by the operating system and therefore your process will be segment faulted by the OS in an attempt by the OS to protect itself.

Gavin
0
kiranghagAuthor Commented:
tomorrow, i'll come with some eloboration on this question, plz wait.
0
tapasmondalCommented:
On the 2nd part, you have defined a pointer of char.It holds the address of the variable. It can't any area of memory. To do this you have to write like as:
tmp=(char *)malloc(N*sizeof(char));
N= length of the area.

thanks,
tapas

0
newmangCommented:
tapasmondal

You should post comments not answers, especially when you are merely repeating information provided previously (on a number of occasions) Unless your contribution is the definitive answer and no-one else has already provided the information then you should comment and let the question writer decide as to whether the question is answered adequately.

Cheers - Gavin
0
kiranghagAuthor Commented:
this is NOTTTTT an answer
i am here to study how to alloc mem
i want a specific answer
plz read the wuestion again and again
0
newmangCommented:
kiranqhaq

Your original question was in regard to why tow different pieces of code produced different behaviours. These questions have been addressed at length and answered many times over.

You now say that you want to study how to allocate memory - this too has been answered in previous posts by me and others but to summarise.

If you want to dynamically allocate memory in your C program you perform the following steps.

1) Declare a pointer of the type required as follows.
char * ptr_fred;

2) Note that at this stage the pointer does NOT point to a valid area of memory and therefore you cannot use the pointer to address memory.

3) Allocate memory and set the pointer to point to that memory as follows
ptr_fred=(char *)malloc(amount_of_memory_required);

4) Check that the pointer is valid (malloc returns NULL on error)
if(ptr_fred==NULL)
   error_state....

5) User *ptr_fred to access the memory

6) Free up the memory as follows:
free(ptr_fred);

7) The pointer variable is once again no longer able to be used to reference memory.

Gavin


0
obgCommented:
Ok, then I might add that when a program starts up it gets a designated data area in memory from the system. Every attempt to write outside this area will result in a segmentation fault. Memory allocations (malloc) will reserve a block of memory within this area. Now, your example
    char tmp[10];
    tmp[21] = 'k';
will put 'k' on the stack where all other local variables are stored. Hopefully you will not destroy any return addresses. When you call a function, the function arguments are first pushed from right to left. Then the return address gets pushed onto the stack. After that the jump is made. In the function the current stack pointer (which points to the return address) is stored, and afterwards it gets decreased (the stack grows downwards) to reserve a hole in the stack for local variables. When the function finnishes, it restores the original stack pointer (jumps the local variables) and jumps to where the stack pointer pointer (!) points (it returns). The caller will then clean up the stack from it's previously pushed function arguments.

If you had done something like:
    char *tmp;
    tmp = malloc(10);
    tmp[21] = 'k';
I THINK you would not get an error since you're probably still within allowed address space, though not space reserved for tmp.

- Hope that some this could help you!
0
kiranghagAuthor Commented:
Doubt solved....
first I ran this

int main( void ) {
       int *a ;
       *a = 10 ;
}

no seg fault...okay

now this

int main( void ) {
       int *a = 10 ;
       *a = 10 ;
}

now there is a seg fault
now did this

int main( void ) {
       int *a ;
       *a = 10 ;
       printf( "\n%d\n", a ) ;
}

i got some int value, say xx

now again did this

int main( void ) {
       int *a = xx ;
       *a = 10 ;
       printf( "\n%d\n", a ) ;
}

no seg fault....that means now my pointer was explicitly initialised in a data $And that for me, proves that compiler doesn't treat pointers and array name as $thanks everybdy
give ur comments, so that i can close the question
0
obgCommented:
Ok. When you declare a variable (doesn't matter if it's a pointer), it's value is undefined. Since local variables are placed on the stack, they can contain anything. You never know what's been there before...

Sorry, but I did not understand what this proves to you...
0
newmangCommented:
kiran

I'm glad we got this sorted out.

The first two code snippets in your last posting illustrate what I and others have been saying all along regarding random memory reference and dereferencing unallocated pointers.

The last two code snippets will never produce a segmentation fault because your are only printing the address of the pointer in your printf statements NOT the memory the pointer points to - you are not dereferencing the pointer. You would be better off in these cases using a printf("%0X\n",a); statement to get the address in hex.

Cheers - Gavin
0
obgCommented:
What??? (Refering to the last paragraph of newmang's comment.)

The segmentation fault has nothing to do with the printf, but with the *a = 10;! I find it very likely that at least the 2nd last snippet will produce a segmentation fault.

But I agree that the "conclusions" are just what we've been saying all along. (Except that I don't understand the proof in the last sentence.)
0
kiranghagAuthor Commented:
does the compiler has
any special treatment for arrays and pointers?

that was my doubt in my third comment.

but now i know it doesn't...

0
newmangCommented:
obg

You are correct re the second to last snippet - I overlooked the dereference of the pointer when looking at the printf. The last snippet won't produce a seg fault because the initialisation of the pointer (int *a = xx) will cause the compiler to generate code to allocate the memory and link the pointer to it.

kiran

The compiler does not have any "special" treatment for arrays and pointers as we have explained previously, the compiler really doesn't know about arrays - it knows a base address and an amount of memory that you, the coder, refer to as ana array - the compiler assumes that you will take care of making sure you do not address beyond the bounds of the array in either direction (it is entirely possible to undershoot an "array" as well as the more normal error of addressing past the end of the area allocate), nor does it have any "special" handling for pointers.

C is a good language in that it allows you to do just about anything you want to but that is also one of it's drawbacks if you are not careful.

Cheers - Gavin
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.