Like Tree12Likes

Whether C++ is a good starting language?

This is a discussion on Whether C++ is a good starting language? within the C++ Programming forums, part of the General Programming Boards category; Originally Posted by JohnGraham My point of view is this: A programming language is a tool. Like any tool, you'll ...

  1. #16
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    22,985
    Quote Originally Posted by JohnGraham View Post
    My point of view is this: A programming language is a tool. Like any tool, you'll learn to use it however you use it. While at the start you'll need to practice the basics again and again, you really start learning it when you really start using it. You'll get used to (and good at) using the features you actually use in real life, and the rest doesn't really matter too much. For example, the majority of C programmers have no use for bit fields in structures, and so will be out of practice using them and possibly even have forgotten the syntax. This doesn't really matter, since this is because they never need to use them.

    The upshot of this is that you should try and actually do as much stuff as you can in your language. And when you do stuff, do it in the way you think is best, not the way that uses some new feature you've just learned about.

    As for your specific question about possibly learning a simpler language, I would advise you to. This isn't advice that everyone would agree with, just mine. I use both C and C++ quite extensively in my work, and C++ is an absolute behemoth of a language. And not just compared to C - I know Python, Java and Lisp all fairly well, and C++ easily dwarfs them by miles. I would say you should learn how to use C well first - this will let you learn things like how to organise and design programs while not getting bogged down in the extensive syntax and subtle semantics of such a huge language. Then when you want to learn C++ you can take the new features it gives you and put them to use where they can really help you in your next programs, as opposed to learning loads of abstract features that you can't clearly envision a use for (as I did in my early days).

    As for having started down the C++ route already, the stage you're at makes it sound like you won't have "wasted" a lot of time if you switch to C now.
    I disagree. Yes, C++ is a big, but then so again, so is Java, C#, and whatever other modern language you can think of. But you don't need to learn it all. You don't need to learn all the subtleties (of which all languages have). Narrow your focus down to a subset of the features that are going to be important.
    If you would just follow a good book (such as this one), I don't think it should be that much harder than any other language.

    Learning C as a prerequisite for C++ is just nonsense. C and C++ are different worlds, kilometers away. You would do well to separate them.
    C is a low-level language with most a do it all yourself attitude, while C++ focuses on expressing high-level code and abstractions while incorporating modern features such as object orientation. The mindset of C and C++ programmers and good and bad practices are entirely different! It only serves to cause confusion and pain to learn the subtleties and the complexion of C, then unlearning all that hard work you poured into learning all that complex stuff because most of it is bad practice in C++.

    And remember that syntax is syntax. Many languages build upon the syntax of C, and many do not. Eventually when learning many programming languages, you have to get used to all the syntax anyway, so I don't think it really matters what syntax you begin with.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #17
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,758
    The mindset of C and C++ programmers and good and bad practices are entirely different!
    No, that's pretty wrong. The reason has nothing to do with programmers, who are people, but the languages themselves.

    C programming is also modular, but the difference is that it is abstraction by parameterization, instead of abstraction by specification. Basically, in C++, you can follow either method. You can do it like C has to, by making enough functions to break a program up into its required tasks. So you can learn procedural programming (which is far more important maybe than actually learning C) by using the same methodology that C has to use. Or you can do it like many object oriented languages have to, by classifying data. C++ is multi-paradigm and it is beautiful (if you ignore the warts of duplicated features, because C++ compiles C, sort of).

    Handling of resources is largely the same. Both try to use RAII. For example, reading a file:
    Code:
    ifstream file("myfile.txt");
    if ( file.is_open() == false ) { logErrors("myfile.txt"); }
    while ( getline(file, stuff) ) { ... }
    
    
    
    FILE *file = fopen("myfile.txt", "r");
    if ( file == NULL ) { logErrors("myfile.txt"); }
    while ( fgets(file, sizeof stuff, stuff) ) { ... }
    fclose(file);
    RAII is extremely common in C because it is easy to do.

    It only serves to cause confusion and pain to learn the subtleties and the complexion of C, then unlearning all that hard work you poured into learning all that complex stuff because most of it is bad practice in C++.
    What makes C painful to a C++ student is the complete lack of C++ features. You cannot learn C++ by using C. If we draw a comparison to human languages, someone learning English as a second language will not find help by studying German or Latin or the myriad of other things it borrows from. A programming-related comparison could be that casting in C is as bad of an idea as it is in C++. But it is pretty much the only way C can do anything "generic". If you wanted the expressiveness of templates, learning C turns out to be a stupid idea.

    For you, I think the only reason to view C as unsafe is its lack of C++ features. But we can tack on a few more: The only reason to view C as a poor way to learn C++ is its lack of C++ features. The only reason to view C++ as a poor way to learn programming is its lack of programming feat-- is because anything worth doing is probably hard for humans. And I can't believe that programming is easy for humans at all, in any language, doing almost anything. If it were easy, it wouldn't make any money. Being literate used to be hard but we don't pay scribes, anymore.
    Last edited by whiteflags; 01-18-2013 at 10:53 PM.

  3. #18
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,256
    Quote Originally Posted by whiteflags
    RAII is extremely common in C because it is easy to do.
    Uh, no. Unfortunately, "RAII" is something of a misnomer. The technique is actually about connecting resource deallocation (and allocation, but sometimes that is not required) to the lifetime of an object such that the resource is deallocated when the object goes out of scope, or is otherwise destroyed. Hence, the C version does not use RAII because omitting the fclose call would be a mistake, even if the variable named file goes out of scope immediately thereafter.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #19
    Registered User
    Join Date
    Jun 2005
    Posts
    6,618
    It is fair to say that C programmers often manually do things that happens automatically in C++. Managing resource lifetime is one of those.



    As to whether C++ is a good starting language, that depends on the person learning it. Generally speaking, however, if the goal is to learn C++ I wouldn't suggest starting with another language.

    I certainly do not subscribe to the viewpoint that C should be learned before C++. If the goal is to learn C, then learn C. If the goal is to learn C++, learn C++. If the goal is to learn Java, learn Java.

    There are simply too many useful techniques in C that are poor practice in C++, and too many useful techniques in C++ that are either poor practice or simply not directly supported in C. That said, it is possible to transition from C to C++, or from C++ to C. It is even possible, with a lot of attention to detail, to learn them both - although I would not advocate that for someone who has never learned a programming language before.




    In the long run, I do advocate learning and using multiple high and low level programming languages. When you learn your second programming language, there is a bit of pain, because there will invariably be habits you have picked up with your first language that are not applicable to your second. That sort of pain continues to some degree when learning subsequent languages. When you get up to half a dozen or so (less if you're lucky, but don't bet on that happening) you start seeing the common ideas and concepts clearly, and also have a perspective to recognise what is distinct about each language.

    And, once you have done work with multiple programming languages, you will realise that it does not matter which one you learned first. All programming languages have their virtues and their pitfalls.

    If you do that then, after a short adventure of fifty or sixty years, you might honestly be able to claim proficiency.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  5. #20
    Registered User
    Join Date
    Apr 2006
    Posts
    2,053
    If you want to learn C++, the surest way is to start by learning c++. If you want to learn to program, I would not recommend C++ to start with. I'd recommend Python. However, In your case, it sounds like you're already far enough into leaning C++ that it's not worth switching. However if you become frustrated with how much you need to learn to do a simple project, you may consider switching languages at that point.

    You mentioned you're starting to learn pointers. They are somewhat demonstrative of why C++ can be a poor starting language. They are tricky to get a handle on, there's a fair bit to know about them, but they are used everywhere, so learning the ins and out early is important. Other languages, like Java and Python, have pointer like things, but they aren't as versatile and also have garbage collection, which together make there be less to learn. But in those languages you cannot choose between passing a value, by reference, by pointer, or by smart pointer as you can in C++.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  6. #21
    Registered User
    Join Date
    Jun 2005
    Posts
    6,618
    Quote Originally Posted by King Mir View Post
    You mentioned you're starting to learn pointers. They are somewhat demonstrative of why C++ can be a poor starting language. They are tricky to get a handle on, there's a fair bit to know about them, but they are used everywhere, so learning the ins and out early is important.
    I disagree that it is necessary to learn the "ins and outs" of pointers early when learning C++. What is true is that C++ has often been taught by teaching C first (in fact, in the early days of C++, that was part of the strategy for gaining a critical mass for C++). Since pointers are traditionally introduced quite early when teaching C, that means pointers have been introduced quite early when teaching C++.

    In C++, it is actually possible to teach a lot about the use of containers and strings - and use them to do lots of useful things - without needing to discuss pointers at all. It is even possible to avoid mentioning raw (C-style) arrays for quite a while, particularly if one avoids delving into the details of C-style strings (i.e. avoiding mentioning that they're arrays with a zero sentinel) and string literals. It is certainly not necessary to teach about pointers in order to introduce iterators (and, in fact, introduction of iterators can be easier if one glosses over the fact that a pointer is a specialised iterator - it is not necessary to teach about pointers before teaching about iterators).

    Yes, it is true that - when learning C++ - it is eventually necessary to delve into the details of raw arrays, string literals, and pointers. But, most teachers of C++ do it too early. However, a few quite successful textbooks have used the approach of leaving introduction of pointers until well after they have introduced containers, strings (as in std::string), and various features of the C++ standard library.


    I also consider it would be possible to teach C, but leave the introduction of pointers much later than has been traditional. It is obviously harder than in C++ to avoid teaching about arrays (since there aren't many alternatives in C) and C-style strings, but there are plenty of useful things (again making use of the standard C library) that can be introduced before it is really necessary to thrust those details upon a student.

    Yes, I realise that this flies in the face of the way C has been taught for a couple of decades. But bear in mind that the teaching of C hasn't actually changed much since K&R days. Pointers were actually an important feature of B and C, as designed by Dennis Ritchie, because they provided a (relative to what came before) higher level abstraction of addresses in machine memory, and ways of operating on addresses that were much cleaner than typical machine languages. And that is the reason that pointers have traditionally been taught early. Not because they have to be, but because pointers were a feature that was of particular interest (rightly) to the creator of C, so he was focused on ensuring programmers learned pointers as early as possible. But, if you were to ask most moderately experienced (or better) C programmers to name the three things that they found difficult to grasp when learning C, it is a fair bet pointers would be frequently mentioned.

    Pointers are actually a very abstract feature of C (and C++), particularly when one includes pointer arithmetic. As laserlight mentioned, quite a few guidelines on teaching programming emphasise the value of teaching concrete "practical" things before teaching abstract things that bend minds out of shape. That suggests the introduction of pointers in both C and C++ should be deferred as much as possible. Not introduced early, as is traditional when teaching C (almost always) and almost-traditional when teaching C++.
    Last edited by grumpy; 01-19-2013 at 07:34 AM.
    jimblumberg likes this.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  7. #22
    Registered User
    Join Date
    Apr 2006
    Posts
    2,053
    Quote Originally Posted by grumpy View Post
    I disagree that it is necessary to learn the "ins and outs" of pointers early when learning C++. What is true is that C++ has often been taught by teaching C first (in fact, in the early days of C++, that was part of the strategy for gaining a critical mass for C++). Since pointers are traditionally introduced quite early when teaching C, that means pointers have been introduced quite early when teaching C++.

    In C++, it is actually possible to teach a lot about the use of containers and strings - and use them to do lots of useful things - without needing to discuss pointers at all. It is even possible to avoid mentioning raw (C-style) arrays for quite a while, particularly if one avoids delving into the details of C-style strings (i.e. avoiding mentioning that they're arrays with a zero sentinel) and string literals. It is certainly not necessary to teach about pointers in order to introduce iterators (and, in fact, introduction of iterators can be easier if one glosses over the fact that a pointer is a specialised iterator - it is not necessary to teach about pointers before teaching about iterators).

    Yes, it is true that - when learning C++ - it is eventually necessary to delve into the details of raw arrays, string literals, and pointers. But, most teachers of C++ do it too early. However, a few quite successful textbooks have used the approach of leaving introduction of pointers until well after they have introduced containers, strings (as in std::string), and various features of the C++ standard library.


    I also consider it would be possible to teach C, but leave the introduction of pointers much later than has been traditional. It is obviously harder than in C++ to avoid teaching about arrays (since there aren't many alternatives in C) and C-style strings, but there are plenty of useful things (again making use of the standard C library) that can be introduced before it is really necessary to thrust those details upon a student.

    Yes, I realise that this flies in the face of the way C has been taught for a couple of decades. But bear in mind that the teaching of C hasn't actually changed much since K&R days. Pointers were actually an important feature of B and C, as designed by Dennis Ritchie, because they provided a (relative to what came before) higher level abstraction of addresses in machine memory, and ways of operating on addresses that were much cleaner than typical machine languages. And that is the reason that pointers have traditionally been taught early. Not because they have to be, but because pointers were a feature that was of particular interest (rightly) to the creator of C, so he was focused on ensuring programmers learned pointers as early as possible. But, if you were to ask most moderately experienced (or better) C programmers to name the three things that they found difficult to grasp when learning C, it is a fair bet pointers would be frequently mentioned.

    Pointers are actually a very abstract feature of C (and C++), particularly when one includes pointer arithmetic. As laserlight mentioned, quite a few guidelines on teaching programming emphasise the value of teaching concrete "practical" things before teaching abstract things that bend minds out of shape. That suggests the introduction of pointers in both C and C++ should be deferred as much as possible. Not introduced early, as is traditional when teaching C (almost always) and almost-traditional when teaching C++.
    Pointer are still an important feature of C++. And because it is "mind bending" you want to devote some time to it. So I would not say you should deferred as much as possible. But I do agree that there are other parts of C++ compete for importance.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  8. #23
    Registered User
    Join Date
    Apr 2006
    Posts
    2,053
    Quote Originally Posted by JohnGraham View Post
    My point of view is this: A programming language is a tool. Like any tool, you'll learn to use it however you use it. While at the start you'll need to practice the basics again and again, you really start learning it when you really start using it. You'll get used to (and good at) using the features you actually use in real life, and the rest doesn't really matter too much. For example, the majority of C programmers have no use for bit fields in structures, and so will be out of practice using them and possibly even have forgotten the syntax. This doesn't really matter, since this is because they never need to use them.

    The upshot of this is that you should try and actually do as much stuff as you can in your language. And when you do stuff, do it in the way you think is best, not the way that uses some new feature you've just learned about.

    As for your specific question about possibly learning a simpler language, I would advise you to. This isn't advice that everyone would agree with, just mine. I use both C and C++ quite extensively in my work, and C++ is an absolute behemoth of a language. And not just compared to C - I know Python, Java and Lisp all fairly well, and C++ easily dwarfs them by miles. I would say you should learn how to use C well first - this will let you learn things like how to organise and design programs while not getting bogged down in the extensive syntax and subtle semantics of such a huge language. Then when you want to learn C++ you can take the new features it gives you and put them to use where they can really help you in your next programs, as opposed to learning loads of abstract features that you can't clearly envision a use for (as I did in my early days).

    As for having started down the C++ route already, the stage you're at makes it sound like you won't have "wasted" a lot of time if you switch to C now.
    The biggest problem with learning C then C++ is that there are a number of things that are good practice in C, but bad practice in C++. This is confusing to new programmers, particular because these things are rarely spelled out.
    Elkvis likes this.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  9. #24
    Registered User
    Join Date
    Oct 2006
    Posts
    2,578
    there is a great deal that you can accomplish in C++ without ever being consciously aware that you're working with a pointer. especially with the advent of C++11, where std::fstream and its friends implement a constructor that takes a std::string as its filename parameter. iterators act like pointers, but with range-based for loops, you can ignore them until you're deep into STL territory.

  10. #25
    Registered User
    Join Date
    Jun 2005
    Posts
    6,618
    Quote Originally Posted by King Mir View Post
    And because it is "mind bending" you want to devote some time to it. So I would not say you should deferred as much as possible. But I do agree that there are other parts of C++ compete for importance.
    I am not arguing that time should not be spent learning pointers. However, that does not mean they should be taught as early as possible.

    The problem with teaching pointers early is that it encourages novices to use pointers for virtually everything, particularly in circumstances where there are effective alternatives available that are less error prone.

    Sure, pointers are an important feature of C and C++. But they are also taught in a manner that encourages their overuse significantly and discourages less error-prone alternatives.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  11. #26
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,395
    Sure, pointers are an important feature of C and C++. But they are also taught in a manner that encourages their overuse significantly and discourages less error-prone alternatives.
    This, in its general form, is why I think teaching a language as a stepping stone to another language is so very flawed.

    Sure, if a language doesn't have "less error-prone alternatives" teach the problematic ones from the start, but for teaching the basics of algorithms and data structures use the format that is least problematic.

    Soma

  12. #27
    Registered User
    Join Date
    Apr 2006
    Posts
    2,053
    Quote Originally Posted by grumpy View Post
    I am not arguing that time should not be spent learning pointers. However, that does not mean they should be taught as early as possible.

    The problem with teaching pointers early is that it encourages novices to use pointers for virtually everything, particularly in circumstances where there are effective alternatives available that are less error prone.

    Sure, pointers are an important feature of C and C++. But they are also taught in a manner that encourages their overuse significantly and discourages less error-prone alternatives.
    I mostly agree.

    The "alternatives" to pointers are smart pointers and references. I agree references should be taught before pointers, but quite possibly not a lot earlier, because pointers are used as optional reference arguments to functions, which is the same kind of thing and it's reasonable that it's taught together. Smart pointers cannot be taught before pointers because they rely on pointers, but they should be taught as the idiomatic way to pass and share control of objects between functions and classes. So you'd teach about pointer syntax and indirection before heap allocation and smart pointers.
    stahta01 likes this.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  13. #28
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,395
    The "alternatives" to pointers are smart pointers and references.
    The intent is that you don't need the pointers, smart pointers, or references to do a lot of stuff if you use containers and related paraphernalia.

    Granted, that would also include iterators which are a generalization of pointers, but with the built in algorithms such knowledge is barely necessary to create sophisticated software.

    I agree references should be taught before pointers, but quite possibly not a lot earlier, because pointers are used as optional reference arguments to functions, which is the same kind of thing and it's reasonable that it's taught together.
    They are not "the same kind of thing" in that context precisely because references aren't optional.

    C++ spells "optional argument" with overloaded functions. You don't need to check for null or even explain what null is in that context. You just have two functions which are called with different parameters.

    Of course, I've seen people get pointers easier than function overloading, but those people usually come from other languages where such a concept is alien.

    Smart pointers cannot be taught before pointers because they rely on pointers, but they should be taught as the idiomatic way to pass and share control of objects between functions and classes.
    It is not only possible; it is to be preferred to teach smart pointers before raw pointers.

    Using smart pointers for single elements and `std::vector' for arrays a beginner can pretty much ignore everything about pointers that cause newbies problems.

    Using smart pointers beginners also get to ignore some stuff related to exceptions, which trips up a lot of C++ programmers even at the intermediate level, because they will not need to understand how coding for exceptions can strongly alter interface design.

    The differences between `malloc', `free', `operator new', `operator delete', the `new' operator, the `delete' operator, the `new[]' operator, and the `delete[]' operator can be set aside for a very long time.

    I know someone is going to say it, so let me get there first: I never use those functions directly unless I'm writing something very low level. You do not need them "to create something non-trivial".

    Soma

  14. #29
    Registered User
    Join Date
    Apr 2006
    Posts
    2,053
    Quote Originally Posted by phantomotap View Post
    The intent is that you don't need the pointers, smart pointers, or references to do a lot of stuff if you use containers and related paraphernalia.

    Granted, that would also include iterators which are a generalization of pointers, but with the built in algorithms such knowledge is barely necessary to create sophisticated software.
    I don't see the merit of delaying teaching the concept of "pass by reference" as late as possible. Sure it's not absolutely necessary for many programs, but it is a pretty basic feature of C++ and can be relevant to writing basic functions.
    They are not "the same kind of thing" in that context precisely because references aren't optional.

    C++ spells "optional argument" with overloaded functions. You don't need to check for null or even explain what null is in that context. You just have two functions which are called with different parameters.

    Of course, I've seen people get pointers easier than function overloading, but those people usually come from other languages where such a concept is alien.
    There's a place for Functional overloading, but it can go against the principle of code reuse, which is something you do want to emphasize early. And there's stuff you can do with pointers that you can't do with overloading. Really, you want to teach both tools.

    It is not only possible; it is to be preferred to teach smart pointers before raw pointers.

    Using smart pointers for single elements and `std::vector' for arrays a beginner can pretty much ignore everything about pointers that cause newbies problems.

    Using smart pointers beginners also get to ignore some stuff related to exceptions, which trips up a lot of C++ programmers even at the intermediate level, because they will not need to understand how coding for exceptions can strongly alter interface design.

    The differences between `malloc', `free', `operator new', `operator delete', the `new' operator, the `delete' operator, the `new[]' operator, and the `delete[]' operator can be set aside for a very long time.

    I know someone is going to say it, so let me get there first: I never use those functions directly unless I'm writing something very low level. You do not need them "to create something non-trivial".

    Soma
    In that context, by teaching pointers I meant teaching about indirection, not about how to manually manage memory. Although as long as you emphasize that smart pointers are preferred over manual memory management, I don't think it's out of place to mention why a smart pointer is needed, and how to manually delete things.


    All I said way pointers "are tricky to get a handle on, there's a fair bit to know about them, but they are used everywhere, so learning the ins and out early is important." I think that applies to C++. It's much more true of C, and I agree you don't want to teach C practices with regards to using them, but even in C++11, pointers are a pretty prominent feature.
    Last edited by King Mir; 01-20-2013 at 03:33 AM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

Page 2 of 2 FirstFirst 12
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to develop good logic in C language
    By rocky in forum C Programming
    Replies: 3
    Last Post: 02-19-2006, 08:52 AM
  2. Java as a Main Language in College Won't Do Good
    By alphaoide in forum A Brief History of Cprogramming.com
    Replies: 23
    Last Post: 01-01-2006, 10:02 AM
  3. Good books on the language?
    By homeyg in forum C++ Programming
    Replies: 1
    Last Post: 12-03-2004, 06:43 PM
  4. Good colleges for language study
    By Lurker in forum A Brief History of Cprogramming.com
    Replies: 2
    Last Post: 10-16-2004, 09:30 PM
  5. Good site to learn about Prog. language concept?
    By Extrovert in forum Tech Board
    Replies: 5
    Last Post: 03-13-2003, 02:46 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21