Do these two lines of code achieve the same result? If I had these lines in a function, is the string stored on the stack in both cases? Is there a strong reason why I should use one over the other, aside from not needing to declare the null terminator in the first line of code?
char s[] = "string";
char* s = "string\0";
No, those two lines do not achieve the same result.
char s[] = "string"
results in a modifiable array of 7 bytes, which is initially filled with the content 's' 't' 'r' 'i' 'n' 'g' '\0'
(all copied over at runtime from the string-literal).
char *s = "string"
results in a pointer to some read-only memory containing the string-literal "string".
If you want to modify the contents of your string, then the first is the only way to go. If you only need read-only access to a string, then the second one will be slightly faster because the string does not have to be copied.
In both cases, there is no need to specify a null terminator in the string literal. The compiler will take care of that for you when it encounters the closing ".