if we free the deleted nodes using free(), then won't this lead to some pretty bad memory fragmentation if your program uses the lists extensively?
Not necessarily. It depends on the usage pattern, the total number of nodes involved, and the details of the allocator involved, among other things. Consider:
Whenever you free a node, you open up a free chunk at least large enough to accommodate a node. If it's not reused for another purpose first then that chunk can be used to perfectly satisfy a future node allocation.
Although some allocators sometimes hand out chunks that are larger in fact than was requested, so that there is wasted space associated with many allocations, not all allocators work that way. Glibc's, for example, does not overallocate in this sense.
If there's not a lot of other memory allocation going on contemporaneously with node allocations, node allocations are likely to be close together, possibly even contiguous.
Long linked lists tend not to be very practical, and modern (virtual) address spaces are enormous. Real-world linked-list usage just can't occupy enough of the address space to produce major fragmentation problems. Unless on systems with highly constrained memory, where any amount of dynamic allocation is usually a non-starter to begin with.
A solution to this could be to allocate a hundred or a thousand nodes at a time, and manage the different chunks, but this seems complicated.
Yes, that can be and occasionally is done. Glibc's allocator does something sort of like that internally. And something along these lines is usually necessary if you want to put your linked list in shared memory, where it can be accessed by processes having separate address spaces.
What would be the preferred method of dealing with this?
If your problem is one that is suited for a linked list in the first place then memory fragmentation arising from that is probably not an issue that needs any special attention. There may be other reasons to avoid per-node allocation and deallocation, but as far as fragmentation goes, the preferred approach is probably to not worry about it once you've settled on using a linked list at all. In other words: don't overthink this.
Would most programs just allocate one chunk of memory for the list and just have this as the maximum number of nodes?
Some programs do take that approach. And some retain removed nodes for reuse instead deallocating them, so that they need allocate new ones only when they don't have any available to recycle. Those fit naturally together, and in combination, they even allow you to allocate additional blocks of nodes. But all of that is usually more trouble than it's worth.