4

I'm at third year of high school and I'm studying C++ at the moment. Since we have done everything that we needed to know about programming in general (loops, if statements, functions, structs, arrays and bidimensional arrays) we started binary/text files and I thought that while we learn files learning memory management. First of all, I'm trying to learn pointers now because, if I understood correctly, in OOP they are a must. Second, I like to know how a computer works, what's behind what's happening. Now, I made this small piece of code

int main()
{
    char y;
    char *x;
    x = &y;
    cout << "Write a word: ";
    cin >> x;
    cout << x << endl;
    system("pause");
    return 0;
}

And it works, but when the program shuts down I get an error that says stack around the variable 'y' was corrupted. If I'm not confused, the stack is the dynamic memory and the heap is the static memory, thinking about that I'm getting this error because the variable y is not in the memory when the program shuts down. Am I on the right path?

Also, one more question. I can't understand when and why I should use pointers, for example:

int main()
{
    int number = 10;
    int* pointer;
    pointer = &number;
    *pointer = 15;
    cout << *pointer << endl;
    system("pause");
    return 0;
}

Why can't I simply do this:

int main()
{
    int number = 10;
    number = 15;
    cout << number << endl;
}

Why should I use the pointer? Also, I don't understand why if I create a char* and assign it, for example "hello" it writes hello and not h. Basically, by declaring a char* I declare an array with unknown size, right? Please tell me exactly what it does.

nobody
  • 19,814
  • 17
  • 56
  • 77
  • Pointers a must for OOP -- only in C++ :) – Fred Foo May 05 '14 at 18:18
  • I still haven't studied OOP, just read a basic article about classes, not sure if I am right by saying that they are a must though. – user3605299 May 05 '14 at 18:19
  • Pointers are quite orthogonal to OOP. You should rarely find yourself using them directly in C++. – juanchopanza May 05 '14 at 18:25
  • 1
    @juanchopanza: Non-owning pointers? Still, newbies tend to grossly overuse raw ponters. – Deduplicator May 05 '14 at 18:27
  • @Deduplicator Sometimes those can't be avoided. But still, they are dangerous. You can index them, call `delete` on them etc. – juanchopanza May 05 '14 at 18:28
  • @juanchopanza: Non-owning pointers are not dangerous. You just mustn't store them longer than they are guaranteed valid nor mishandle them that way. But that goes for all objects. – Deduplicator May 05 '14 at 18:32
  • @Deduplicator all pointers are dangerous, because the language allows you to perform all kinds of operations on them which you shouldn't. That's one of the reasons people are proposing `std::observer_ptr`. – juanchopanza May 05 '14 at 18:35
  • 2
    Newbs overuse pointers to the point that I've seen `{vector *v = new vector; /*use vector*/ delete v;}` in production code. I blame Java. Not only is its `new` keyword entirely redundant syntax, it makes programmers think that it's required to make objects in any language that has it. – Fred Foo May 05 '14 at 18:39
  • @juanchopanza: Just googled it, and that was *not* a reason, but rather documenting in a legacy API environment that now this one really is a non-owning pointer. The proposal does at most send mixed messages for new code. – Deduplicator May 05 '14 at 18:44
  • 1
    Well asked question by a new user. It has been a while since I've seen one :) – sealz May 05 '14 at 18:48
  • Rules of thumb: 1) You never *need* to use a pointer in C++. 2) There are exceptions to rule #1. – John Dibling May 05 '14 at 18:50
  • 1
    @larsmans Apparently [not entirely redundant](http://stackoverflow.com/questions/6340535/is-the-new-keyword-in-java-redundant), but probably more by accident than design :-) But I agree with you completely. – juanchopanza May 05 '14 at 18:50
  • Wow, you learned everything about general programming in high school. How about data structures, design patterns, and function pointers? – Thomas Matthews May 05 '14 at 19:57
  • Learning all of those is my next step. – user3605299 May 06 '14 at 04:23

2 Answers2

5

when program shuts down I get an error that says stack around the variable 'y' was corrupted

Because >> responds to a char* by accepting an entire string. The pointer must point to a large enough buffer to hold that string, but it only points to the stack variable x. >> doesn't know that, so it just charges ahead and writes over whatever is next to x on the stack.

Actually, you'd better use std::string in this case:

std::string s;
std::cin >> s;

reads a word from cin.

Why can't I simply do this

You can. You don't need pointers in this simple program, but you will need them for more advanced stuff. Even if you don't use them a lot (modern C++ has many facilities to replace strings by safer and easier constructs), it still helps to know that std::string, for example, is implemented using pointers: it's really a char* wrapped in a class that takes care of things like >> for you. The class knows where the char* points and adjusts it if it needs more space to store extra characters.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Before C++11, it could have been a more involved structure, and even with C++11 it needn't contain a pointer for small strings (small string optimisation). Still +1 – Deduplicator May 05 '14 at 18:29
  • 1
    @Deduplicator: consciously simplifying for the sake of education :) (Was there any C++98 implem that did *not* make `std::string` a wrapper around a nul-terminated C string?) – Fred Foo May 05 '14 at 18:33
  • If there had been one (internal storage for small-string-optimisation), C++11 would never have fastened the screws there. – Deduplicator May 05 '14 at 18:57
2

In the first section, you declare y to be a single char: not an array of them. So when you try to read in a word, only the first letter "fits" within that single char space. The rest of the characters that are read in will actually "overflow" the space you had allocated for it, giving you those errors.

If you want to have more letters, you need to define y as an array of char, so either:

char* y = new char[50]; // Create an array of 50 chars, on the HEAP, not the stack

or

char y[50]; // Create an array of 50 chars, on the STACK, not the heap.

Think of a STACK as an area within your house. Your house isn't HUGE, but it's large enough for you to do most of the necessary things. You can pile 50 boxes in a corner of the room, and when you leave the room, your maid comes along and gets rid of all those left-over boxes for you. You don't have to manually clean them up.

Think of a HEAP as an extremely large storage locker. You, and every other program running on your computer, share space in this storage locker. Whenever you need some additional space, you "rent" a small room within it, and are given a piece of paper with the room's (memory) address written on it. This piece of paper can be copied, so any of your friends who want to get into your boxes can do so.

So you go to the storage locker, and request a room that will fit 50 boxes. They hand you a piece of paper with the (memory) address of that room. You can use up as much of those boxes in that room as you want: it's yours.

You can even give the address of your room to your friend x. Your friend x can access the boxes, change stuff within the boxes, and go to town with the content of your room. But x cannot change the location of your room. x can also share the (memory) address of that room with others if he wants.

Now, you are done using your room. If you throw away your paper with the address of your room, the room is still allocated with your name on it. But you don't have access to it anymore, since you don't know its address. But if your friend still has a copy of your paper, THEY can still access the contents of your room. That's like allocating char *y = new char[50] and then simply exiting the function without deleting y first.

If everyone discards their papers with your room's (memory) address on it, the room is still there, and you now have "leaked memory": it's been allocated, but no one points to it. It will remain unused for the lifetime of your program.

Let's say that, before you are done with your room, you inform the storage manager that it's free to clean up: you're moving out. The manager unregisters your room: you have no "leaked memory." That's like using delete [] y before you close the function.

The one caveat is that something bad can still happen: If you, or your friend x, still point to the room after it's been unregistered with the storage manager, and you try to access it now, that becomes a problem: the boxes MIGHT still be there, but there's a good chance that someone else is now using up some (or all) of that space, and you're looking at the contents of THEIR room. You want to avoid that.

All of the stuff in your example is just fancy ways of saying "give my friend the address of that memory." Sure, you have access to it, but now a friend can point to it as well.

OnlineCop
  • 4,019
  • 23
  • 35
  • It's a good thing the heap is seldom shared between programs, and often each thread has its own heap/heap compartement. – Deduplicator May 05 '14 at 18:47
  • Nice explanation! Thanks! Thinking about the heap and the stack, does that mean that I can create an array of N size by using a pointer and the new keyword? For example, I want to write a name by using an array of chars but I don't know how many letters the name has, without a pointer I'd normally create an array of about 20 elements and ask the user how many letters the name has, but with a pointer can I ask hte number of how many letters the name has and then create the array with the given size? for example, char* word = new char[size]; would that work? – user3605299 May 05 '14 at 18:50
  • @user3605299: try it and see :) – Fred Foo May 05 '14 at 19:06
  • @user3605299: Yes. If you prompt for the length of the word first, you can then dynamically create your array with that many characters using that `char* word = new char[size];` notation. If you use C++, the `std::string` does this intelligently: It allocates "some" space for text, and as soon as you try to add more to it than it can hold, it actually requests a larger "room", copies all of contents from the "smaller" room into the "larger" room, and destroys the "smaller" room. It's done behind-the-scenes so you don't have to know how much space you need ahead of time. – OnlineCop May 05 '14 at 20:18