In C++ if you declare a character array that is initialized by a string literal and you specify explicitly the number of elements in the array you need also take into account the terminating zero character '\0' that is implicitly present in the string literal. For example
char s[6] = "Hello";
^^^
This declaration is equivalent to
char s[6] = { 'H', 'e', 'l', 'l', 'o', '\0' };
In C you may ignore the terminating zero character of a string literal when you declare a character array. For example
char s[5] = "Hello";
^^^
This declaration is equivalent to
char s[5] = { 'H', 'e', 'l', 'l', 'o' };
But in this case such a character array does not contain a string. So for example using such an array within the function puts like
puts( s ):
or in most standard string functions invokes undefined behavior.
Of course you could declare the array without specifying explicitly the number of elements in the array if you want to initialize it by a string literal and guarantee that the array will contain a string.
char s[] = "Hello";
This declaration is equivalent to
char s[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
and the declared array will contain exactly 6 elements.
Edit: After you appended your question with this code snippet
const char* a = "Hello";
a[5] = '\0';
char* b = new char[5];
b[5] = '\0';
char c[5];
c[5] = '\0';
then you may not change an object using a constant pointer to it like this
const char* a = "Hello";
a[5] = '\0';
Moreover if you will remove the qualifier const (in C string literals have types of non-constant character arrays opposite to C++)
char* a = "Hello";
nevertheless you may not change a string literal. An attempt to change a string literal in C and C++ results in undefined behavior.
In this part of the code snippet
char* b = new char[5];
b[5] = '\0';
char c[5];
c[5] = '\0';
you are trying to access memory beyond the allocated arrays because the valid range of indices is [0, 4] that again invokes undefined behavior.
Instead you could write for example
char* b = new char[5]();
char c[5] = {};
In this case the arrays will be zero-initialized.
Or you could write
char* b = new char[5];
b[0] = '\0'; // that is the same as *b = '\0';
char c[5];
c[0] = '\0'; // that is the same as *c = '\0';
In the both cases the arrays will contain empty strings.