According to your comment the array will never change, you should make it constant. Also use pointers to the entries. The latter avoid the need to provide the max. size of characters per "string" and avoids waisting space:
const char * const list[][2] = { { "...", "..." } , ... };
This is a 2D array of pointers to char. The initialiser will set the pointers to the string literals given in the initialiser. This is the most comfortable (in the sense of automatic memory space sizing) you can get. The compiler can deduce the outer (leftmost!) dimension by the number of pairs in the initialiser. For the inner dimension, you have to specify. The sizes of the strings literals are not relevant for the array, as we use pointers (the data is not stored in the array itself).
The first const tells the compiler the object pointed to will not be modified. The second tells the same for the pointer itself (which implies the whole array will not be modified).
With this, you can use strcmp as you used in your question:
strcmp(list[i][0], data)
Make sure data is always properly terminated (i.e. '\0' at the end).
Update: According to your edit, you want to access the second entry as a number. Maybe an integer would then be better than a string. For this, you need a 1D array of a struct:
const struct {
const char *name;
int number;
} list[] = { { .name = "name", .number = 15 } , ... };
(The .name =/.number = parts are designated initialisers; standard since C99.)
Usage:
strcmp(list[i].name, data)
int my_number = list[i].number;
That way you may process the integer part easier and you name both entries easier. Even if you still use two strings, this might be the better approach, because you should use arrays only if all entries have the same semantics, otherwise a struct would be more appropriate.
char **list[][]would be? Don't just do trial and error.char **list[][], is not a pointer to a 2d array of char, instead it is 2d array of pointers which hold addresses of pointers of chars, you just can't initiate that way.