The hard bit about programming is learning the concepts. Learning the language itself is the easy part.
Generally this is quite true. Anyone undertaking a causal or unstructured approach to learning is going to have a longer road learning the concepts behind the science, simply because they're not usually among the things you learn in short on-line tutorials or many of the books that cover a particular IDE (Like those that focus just on XCode or Visual Studio).
It's something like learning the alphabet and the grammar, but then having to figure out just what to say; how to paint a picture in words, set a scene, build a narrative up from smaller details. You don't want your applications to work and act like a kid telling a story with a series of "...and then, he goes like...." - all delivered as if they were a series of questions.
In the higher levels of C++, theory and language begin to merge, and the study isn't particularly easy. Templates, for example, support generic programming and an alternate form of polymorphism, which can't be used simply by knowing the language.
To expand on a point I made earlier (which the OP mentioned was confusing), for the Mac there are three languages involved; objective-C (the part that's unique and NOT C), C, and C++.
C++ was designed to 'absorb' C. When you write in C++, you have a significant blend of the older C syntax within primitives. That is, the use and organization of an object is similar in C++ to that creation of a struct in C. There are minor extensions made to turn a C struct into a C++ object. For objective-C, however, the 'syntax' used to create an object is entirely different from C (or C++), and appears to be a completely different language 'tacked on' to C (some don't like this, others suggest it's a benefit). There is an 'interface' between these languages which must be understood, especially in Mac development, where all 3 may be involved.
You can simply obviate the problem to two languages by deciding NOT to use C++. For the purposes of a 'divide and conquer' plan on learning this stuff, that's probably wise, but C++ is far better for most application use than C. However, there's that interface between the languages, and since objective-C was designed before C++ was generally available, even with objective-C, the interface between the languages is based on C level concepts.
Here's what I mean using a small example.
Objective C makes use of NSRect. Most of the objects in AppKit are 'genuine' objective-C objects, and all of them are named beginning with NS. NSWindow, for example, is an objective-C object representing an operating system object (the Window, obviously), and it has some data associated with the window. NSRect can be used to define the size of the window, but NSRect is presented as a C style struct, not an objective-C object. This struct has a point (the lower left corner), and a size (width and height). NSRect looks the same in C++ as it does in C, but it can be used differently.
In C, to copy the contents of the NSRect from one to another, you can't say this:
NSRect r1, r2;
...assume r2 is setup with some values
r1 = r2;
The line 'r1 = r2' is an assignment, and C doesn't 'know' how to do this for you. In C, you have to use something that copies the memory from r2 to r1, or copy each member value within the NSRect struct. In C++, a default 'assignment' operator is created, so r1 = r2 makes sense to the compiler. In C, a struct is just a way of 'structuring' some related data together, but it doesn't 'do' anything beyond that. In C++, a struct is an 'object' - the same as a 'class', differing only in default permissions. As a result, you can 'do' things with NSRect in C++ that you can't do in C.
In C, r1 = r2 might be replaced with;
memcpy( &r1, &r2, sizeof( struct NSRect ) );
Note quite as obvious is it?
In C, you might also use;
r1.origin.x = r2.origin.x;
r1.origin.y = r2.origin.y;
r1.size.width = r2.size.width;
r1.size.height = r2.size.height;
If you extrapolate this oversimplified example to the complexity of more advanced development, perhaps you can see why someone who knows C++ well would much prefer C++ (and thus, r1 = r2 ) as the accompaniment to objective-C, instead of C.
Unfortunately it's not entirely that simple (though close).
The 'interface' between C++ and the 'objective' part of objective-C aren't formalized by outside standards bodies the way the C and C++ languages themselves are handled. As a result, there are a few rough spots that require you to understand at least some of the 'C' components in this mix. However, you can easily discover them (well, relatively) as part of a study of C++, rather than as a study of C.
For C programmers learning C++, there must be a host of practices, common in C, which must be 'unlearned' in order to apply replacement techniques used in C++. Habits learned as a C programmer must be dropped, and habits are hard to break. The best way to avoid 'bad C style habits' is not to pick them up in the first place, and learn C++ before learning C. Many think this is backwards, because, in my learning days, I had no choice. C++ didn't exist; I had been a C programmer for years before C++ was created. The language was designed, after all, to allow C programmers to gradually adapt to OOP/OOD techniques.
The reality, though, is more associated with practices common to C development. The use of 'smart pointers' in C++ is one primary focal point. C uses 'raw pointers' - the same kind used in assembler programming. C++ can use them, too - and most of us did that for a long time (especially before templates were implemented to permit the creation of smart pointers).
Smart pointers avoid a great many debugging hours and fragility in working code that is simply too important to ignore. C programmers might find them annoying or unnecessary, opting for the familiar 'raw' pointer. Learning to USE advantageous constructs like the smart pointer, before learning something more prone to bugs and design flaws, gives a base of 'better habits' upon which to build one's own practice. It is for this reason (extrapolated out to dozens if not hundreds of such concepts) that learning C++ first is a better choice.
If the 'learn C first' concept is based on knowing 'the base most concepts' first, then the logical extension of that logic would mean you should start with assembler first. Clearly that's not helpful, but it can work (I came from that path). It's much easier to learn concepts that work best, and later, to dive under the hood and see what it takes to make that happen, digging DOWNWARD toward the raw machine, rather than upwards toward higher organization.
Taking that to a logical extension, it's probably better to 'start' the study in Java, Python or related languages.
I'm not one to point, though. My first exposure to programming was on a 6502 based machine, using assembler. When I 'dabbled' in BASIC occasionally, I resorted to 'poking' machine language code in there to make things actually run. To me, C was a 'rescue' of sorts. We've come a long way from that time, and there's decades of ground to cover between 6502 assembler and modern languages and operating systems. The older timers, like me, lived through it so you won't have to