The {0, } initializer is the same as the more common {0} initializer.
The trailing comma is allowed by the syntax but it makes no difference.
6.7.9--Initialization:
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designationopt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier
The semantics are such that the 0, which is syntactically required because at least one initializer-list item is syntactically required (it's a kind of a arbitrary requirement: compilers frequently support an empty {} as well) initializes the first subobject recursively (6.7.9p17):
Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union.148) In contrast, a designation causes the following initializer to begin initialization of the subobject described by the designator. Initialization then continues forward in order, beginning with the next subobject after that described by the designator.
and the rest is initialized as it would be if the whole object had static storage duration (6.7.9p19,6.7.9p21). This practically means to 0 (as with memset(,0,) although with the caveat that paddings need not be initialized and that 0-initialized pointers need not necessarily be "all-bits zero".
As far as I know, compilers on usual platforms (where pointers are all-bits-zero) just mostly do what they would do with memset(,0,).
This "universal" zero initialization works because the first 0 will recursively hit a scalar type (number on pointer) which can be invariably initialized with the 0 initializer. The default "as-with-static-storage-duration" then initialization applies to the rest.
A perhaps slightly more interesting of the trailing initializer comma doing nothing would be:
int main()
{
char one[]={0,}; //<the comma doesn't introduce another member
_Static_assert(sizeof(one)==1,""); //holds
}