why does the following code changes its output when I replace virtual void f() in class A with void f()? (it prints B when void, C when virtual void)
When a class inherits from another (like in your case B and C from A and B respectively), the virtual keyword means that the method it is applied to (f()) in your case) can be re-defined for child classes. In your case, it allows classes B and C to have their own personal implementations for f(), through polymorphism. Notice how in your main() you create a C object, and not a B:
B *p = new C;
it seems confusing because the address of that C object is stored in a B pointer, but is is legal in C++ because a C object is in fact B object, because it inherits (has a "is a" relationship) from B. When you call f()on that B pointer storing a C object, polymorphism is enabled because the method is virtual: it selects the C-version of the f() method, and that is why you see a C printed.
When you remove the virtual polymorphism is disabled the the C object is seen as a B object, and the B-version of f() is selected. Then you see "B" on your screen.
Why does the following code print more than "CPP!"?
From this, it says that: 
The switch statement has a somewhat peculiar syntax inherited from the
  early times of the first C compilers, because it uses labels instead
  of blocks. In the most typical use (shown above), this means that
  break statements are needed after each group of statements for a
  particular label. If break is not included, all statements following
  the case (including those under any other labels) are also executed,
  until the end of the switch block or a jump statement (such as break)
  is reached.
So, try this instead:
int main ()
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    for(int y:x)
    {
        switch(y)
        {
            case 1:cout<<"C";break; // <- notice the 'break'!
            case 3:cout<<"P";break;
            case 7:cout<<"P";break;
            case 8:cout<<"!";break;
        }
    }
}