Take a look at https://github.com/stevennl/Snake, a project demonstrating a few AI algorithms for the game Snake. The project README has a very nice explanation of the algorithm.
The key is for the snake to follow a Hamiltonian circuit (a path that visits every square, and loops back on itself). Many such paths exist for a simple 2D grid, you just have to find one. So something like this:
Finding such a path is also known as the longest path problem. If you make your AI follow this circuit, it will never trap itself and will be able to grow to the largest size possible - filling the entire grid. If you're lazy you can stop here - your AI doesn't even need to care where the fruit is. Of course, this AI will be horribly slow, and maybe boring to watch.
To make the snake faster at eating fruit, you can make it take shortcuts within the Hamiltonian circuit, as long as taking such shortcuts won't make its head overlap its body after taking the shortcut. Here's an image covering the key points:
This algorithm is much better, but still not the best, since it is still following the original Hamiltonian circuit. It's possible that finding other circuits will allow it to take better shortcuts.