I always use p for pointers, but not p_. Mainly it's because of aesthetics when scanning code. The -> operator and the _ always break things up too much for my brain. If I'm in a well protected piece of code where I know I don't need to do null check, I may write something like this:
pFoo->pBar->pBaz=blah;
with the underscore, I find that much harder to parse (probably just my dyslexia, but maybe it's useful for you too). This is much harder for me to read. p_foo->p_bar->p_baz=blah;
Another thing that I've learned over the years is any time I need to do a malloc, make it typed-ish and have an accompanying free. Sometimes you may need to use a different library or a different allocator and then you have conflicts on who creates something and who deletes it. So I always have paired foo* new_foo();
void delete_foo(foo* pFoo);
bar* new_bar();
void delete_bar(bar* pBar);
baz* new_baz();
void delete_baz(baz* pBaz);
Those functions may simply be wrappers around a malloc/free, or they may be more complex, but I like to start with having them exist in case I need to change the implementation later. When you're managing your memory, try to make it hard to make mistakes.I do mostly agree with the other commentors though, just dig in an have fun and learn what works for you.