There's more than one kind of "list". The implementation you show is a "Linked List". Without pointers there would be no "links", so we'd need to look at other kinds of lists.
So, first up, what happens if you just remove the *
from the struct definition: it won't compile. You can include a struct inside of another struct, but if there's recursion then the structure will have infinite size that isn't going to happen!
How about an array as a list:
struct item list[100];
Yep, that'll work, but now your list is a fixed size.
Ok, so let's dynamically allocate the list:
struct item *list = malloc(sizeof(struct item));
Then, everytime you add to the list you'd have to do this:
list = realloc(list, newcount * sizeof(struct item));
list[newitem] = blah;
OK, that works, but now we're reallocating memory frequently, and that leads to lots of memory copies, and inefficiency.
On the other hand, if the list is updated very infrequently, this is more space-efficient, and that might be a good thing.
Another disadvantage of using an array is that operations such as push, pop, sort, reverse, etc. become much more expensive; they all mean multiple memory copies.
There are other kinds of "list", but they all involve pointers, so I think we can disregard them here.