Look at the line 5:
char * const p
Here ptr is a constant pointer to a variable of type char, and we can not modify the ptr value at line 6.
To understand such complex declarations you need to learn reading Complex Declaration using Right-Left Rule. Here is a small walk through to read declarations like this:
Starting from the variable name first consider what is written on the RIGHT hand side of variable name , then Look at what is present on the LEFT hand side, then again see what is present on the right hand side, go on like this till the whole expression is read.
If a semicolon is encountered on the Right side, only read the Left side.
Consider the expression: int **ptr;
Step 1. Here the variable name is "ptr"
Step 2. See what is present on the right hand side of the variable name , i.e.  (square brackets)
EX. It means ptr is an array (ptr)
Step 3. Now look at the left side of ptr, a * is present which means:
ptr is an array of pointers (*ptr)
Step 4. Again look at what is present on the right hand side of the expression already read i.e.
what is present on the right side of *ptr, Nothing is present, So we will look at the LEFT side of the expression, a "*" is present which means
ptr is an array of pointer to pointer (**ptr).
Step 5. Since there was a semicolon at the Right side, we will only look at Left side . The keyword int is present. Hence,
ptr is an array of pointers to pointer of integer type variables (int **ptr)