Now I may not have to worry about this now since I'm in the learning stage, but once I start developing and writing my own programs I would like to document the code properly
For starters, each module should begin with a block comment describing its purpose, and any tricky details/gotchas which would be relevant to someone trying to use the functions therein.
Individual functions should have a similar block comment which describes what the function does, describes the arguments and return value, and any side effects.
Anything in the code itself which may not be obvious to someone else (or to yourself several years hence) should have a brief inline comment explaining what's going on.
Members of data structures should all have a brief description (comment) as well, if their purpose isn't intuitively obvious from the member name/type.
In more formal (e.g. commercial development) contexts, a tool like Doxygen
is sometimes used. By putting special tags (markup) in the comments, the tool can extract design documentation from the code, and that documentation can then easily be published (e.g. on a web site). That would be a distraction at this early stage, but you may want to look at it down the road.
and keep the code portable across platforms so other people who find my stuff useful are able to compile and run it on their preferred platforms including Windows and MacOS.
Portability between Windows and *NIX platforms can be a PITA in C unless you're using 3rd party libaries to hide the differences in OS system calls. That's one of the advantages of languages like Python which present a higher level of abstraction -- the language hides many of the OS details from you. For small applications it's reasonable to write your own simple wrapper functions, with code inside those wrappers conditionally compiled via #ifdef directives for different platforms; this is also a good way to teach yourself about the differences in APIs between OSes.
At a lower level, don't assume that the generic integer data types (short, int, long, long long) have the same size across different platforms, and don't count on pointers having the same size as any particular integral type either. IIRC the only guarantees you have are that short is at least as large as char, int is at least as large as short, etc.
Also don't count on the bytes in integral types being stored in memory in the same order (endianness) across platforms. While this will be "mostly harmless" if you stick to x86, it will trip you up if you ever try to run the code on a non-x86 architecture that uses big-endian byte ordering like IBM POWER. Don't rely on any particular memory layout for members of a data structure either; e.g. if you have a struct which contains a char followed by an int, don't assume that the int starts at the 2nd byte of the struct (compilers will typically align scalar members to a multiple of the member's size, so on a platform with 4-byte ints the int in the above example would start at the 4th byte, with 3 bytes of unused padding).
GUIs are particularly problematic from a portability standpoint, unless you're using a cross-platform GUI toolkit like GTK+ or Qt. Learning those toolkits is a major undertaking in its own right; I generally don't write end-user facing code these days, and haven't had enough motivation to learn them myself beyond the bare basics (just enough to patch the occasional bug in a Linux application that is pissing me off).
Edit: Why are we discussing this here, instead of in your C thread?