I'm trying to learn C. Since I have already some familiarity with higher level languages (PHP, Javascript, Python) I feel most of the work I have to do involves learning how to replace structures which I would give for granted (say variable sized arrays) through the use of pointers, and manually managing memory. My problem is that I am a bit worried about playing with pointers.
Usually I try to experiment with other language features, but my problem is that a bad use of pointers could have unexpected results. I开发者_StackOverflow中文版n particular: is it possible - if I make a mistake - that I may corrupt memory segments that other programs are using, causing those programs to misbehave? Or will the operating system, (in my case various flavours of Ubuntu) prevent me to intefere with the memory assigned to different processes?
In the former case I guess it would be possible (though unlikely) that I may cause other programs to write bad data on the disk, corrupting some information I have on the hard drive. Or even worst (and even more unlikely, I guess) it could damage some hardware - for instance older monitors could be burned by software which would set an out of range refresh rate.
I know that probably my worries are not justified, but I would like to know how far the compiler/operating system will prevent me from doing dangerous operations when I make a mistake managing pointers.
In particular: is it possible - if I make a mistake - that I may corrupt memory segments that other programs are using, causing those programs to misbehave?
Not on most (all?) major operation systems available today. Memory protection has been a feature of most Unix/Linux systems, Windows, and Mac OS for a decade. Memory protection is an OS level access control system that prevents programs writing to memory that doesn't belong to them. This is both, as you suggest, to prevent software writing into memory that belongs to other processes, but also to prevent software from reading memory that doesn't belong to it (a major security risk).
That's not to say it's something you may not have to worry about in the future, but if you're starting off learning C on a modern desktop it's something you shouldn't really think about. If you make a mistake in your C code you're probably not going to cripple the OS! :)
It's a very interesting topic, and one I think everyone would benefit from knowing about. You'll almost certainly run into situations when you're learning when you try to access memory that doesn't belong to you and your process is terminated by the system. Check out these two wiki articles for more information:
http://en.wikipedia.org/wiki/Buffer_overflow and http://en.wikipedia.org/wiki/Memory_protection
Corruption and crashes are possible, but as long as you are careful with the size of value in memory the pointer points to, and you are sure you don't interchange pointers, and you are sure you DON'T HARDCODE MEMORY ADDRESSES you should be fine.
You cannot affect other processes except for some rare OSes. You can obviously not damage any hardware. (If that would be possible, my iOS device would be burned a long time ago due to about every app in the app store contains memory faults because programmers are too lazy to read the damn documentation.)
Good example
int *i = malloc(sizeof(int));
// Use I further.
free(i);
Wrong example
int *i;
i = malloc(sizeof(int));
double j;
i = &j;
j = 3.1415// Mem corruption due to differently sized values, given a double is LARGER than an int.
(Not sure if this compiles. Depends on the compiler flags.)
Terrible example, 99% guaranteed corruption
int *i = 0x00ABCDEF; // Hard coded mem adress.
int j = 123;
int *k = &j;
memcpy(i, k, sizeof(int));
Most modern, desktop-oriented operating systems (including Linux) use virtual memory to prevent a misbehaving program from disrupting other programs. Each process gets its own address space, and if you overflow a buffer or similarly misuse pointers, about the worst that can happen is you crash your process. You shouldn't affect other processes in the system unless you're writing a device driver or running as root (and if you're running as root, you'd have to do something bad to a file another process is reading, etc... you still wouldn't have direct access to another process's memory).
In terms of catching errors before you make them, here are some rules to follow that can help you:
- Always check any newly-received pointers (such as return values of
malloc
, function arguments, etc.) for null before using them. - Turn your compiler's warnings all the way up and pay attention to them.
- After
free
ing dynamically allocated memory, set the pointer to null. This should help you catch some dangling pointer or double-free errors. (Of course, if you've copied that pointer and stored it in other places in your code, you could still have these problems unless you're careful.)
In most modern operating systems (Linux included) each process runs in a separate address space, which means that all the memory that it can address is not real RAM, but its own private "memory sandbox", that do not affect other applications (actually it could if you had RW memory segments shared with other applications you could, but you and the other application have to create them explicitly).
By the way, often if you do mistakes with pointers you end up with pointers which point to invalid memory locations, and the first time you'll try to dereference them the OS will shut down your application with a segmentation fault; don't worry about it, it's just the OS telling you you're doing mess with pointers. :) The most serious problems, on the other hand, are those where the OS can't detect that you got some pointer stuff wrong.
精彩评论