For a daemon, what you want is a process that has no tie to anything. At the very least, you want it to be in its own session, not be attached to a terminal, not have any file descriptor inherited from the parent open to anything, not have a parent caring for you (other than init) have the current directory in / so as not to prevent a umount...

To detach from a terminal, you create a new session, however, to create a session, you must not be a group (or session) leader, so best is to fork a new process. Assuming the parent exits, that also means that process will not have a parent anymore and will be adopted by init. Then, close all possible file descriptors, you chdir("/") (one can't close the current working directory to release that resource like for file descriptors, making / the current working directories at least doesn't prevent unmounting directories).

Because that process is a session leader, there's a risk that if it ever opens a terminal device, it becomes the controlling process of that terminal. Forking a second time ensures it doesn't happen.

On the other end, &, in interactive shells, forks and creates a new process group (so as not to be in the terminal's foreground process group), and in non-interactive shells, forks a process and ignores SIGINT in it. It doesn't detach from the terminal, doesn't close file descriptors (though some shells will reopen stdin to /dev/null)...

The difference between running a program/process as a daemon and forking it to the background using the ampersand is basically related to ownership.

Most often, the parent process of a daemon is the init process (the very first process to be started on a Unix system), the daemon being a child of that process means that it is not under your direct control as an non-privileged user. While on the other hand, forking a program/process to the background means that you can at any time call it back to the foreground and/or kill it.

With command & Your process will be killed by a SIGHUP signal when the parent dies.

Sysadmins have access to some workarounds, though.

On a bash system, you can use:

(trap '' HUP; command) &

This opens a subshell, traps the HUP signal with an empty handler and ampersand/forks it.

Output might still get redirected to the wrong tty. Or get lost.
You may fix that with &>command.out, 1>output.out, or 2>errors.out

You might also have access, on most systems, to the nohup command.nohup simplifies this process greatly. It's quite standard, but I found many busybox embedded ARM distributions missing it. You just write:

nohup command &

..and you're done. Output gets redirected, IIRC, to nohup.out, but this filename can be changed with an option.