size_t é um tipo de dados unsigned integer (isto é, pode ser do tipo unsigned short, int, long, ou long long) que é definido em vários arquivos de header como:
- <stddef.h>
- <stdio.h>
- <stdlib.h>
- <string.h>
- <time.h>
- <wchar.h>
É um tipo de dado que é usado para representar o tamanho de objetos em bytes e é, portanto, usado como retorno do operador sizeof. É garantido para ser grande o suficiente para conter o tamanho do maior objeto que o sistema pode suportar. Basicamente o maior tamanho permitido depende do compilador, se o compilador é 32 bit então é um typedef (alias/apelido) para unsigned int, mas se o compilador for de 64 bit então seria um typedef para unsigned long long. O tipo de dado size_t nunca é negativo.

Qual a diferença do size_t para o unsigned int?
Como dito anteriormente, o tipo size_t provavelmente será maior que, igual que, ou menor que um unsigned int, e seu compilador fará suposições sobre a otimização.
Por que não usar só o unsigned int?
Porque ele provavelmente não será capaz de suportar números grandes o suficiente. Em uma implementação onde unsigned int é 32 bits, o maior número possível a ser representado é 4294967295. Alguns processadores como o IP16L32, pode copiar objetos maiores que 4294967295 bytes.
Então por que não usar um unsigned long int?
Porque exige um custo de desempenho em algumas plataformas. O padrão de C exige que um long ocupe pelo menos 32 bits. Uma plataforma IP16L32 implementa cada 32-bit long como um par de palavras de 16-bit. Quase todos os operadores de 32-bit nessas plataformas exigem duas instruções, senão mais, porque elas trabalham 32 bits como dois pedações de 16 bits. Por exemplo, mover um 32-bit long frequentemente exige duas instruções da máquina – uma para mover cada pedaço de 16-bit.
| ILP32 | LP64 | LLP64 | ILP64 | |
| char | 8 | 8 | 8 | 8 |
| short | 16 | 16 | 16 | 16 |
| int | 32 | 32 | 32 | 64 |
| long | 32 | 64 | 32 | 64 |
| long long | 64 | 64 | 64 | 64 |
| size_t | 32 | 64 | 64 | 64 |
| pointer | 32 | 64 | 64 | 64 |
Algumas funções que usam o size_t
void *malloc(size_t n);
void *memcpy(void *s1, void const *s2, size_t n);
size_t strlen(char const *s);
Referências
https://www.geeksforgeeks.org/size_t-data-type-c-language/
https://stackoverflow.com/questions/131803/unsigned-int-vs-size-t
https://www.viva64.com/en/a/0004/
https://www.quora.com/When-do-you-use-unsigned-int-vs-size_t