c.append(b[j])
adds into c a reference to the object b[j].
Thereafter, changing c[j] changes b[j].
To avoid this, produce a copy, of b[j], instead:
c.append(copy.copy(b[j]))
That requires import copy.
Indeed, Python tends to use references instead of copying elements, with certain exceptions (e.g., dict .copy, slicing, sorted(), dict .get() produce shallow copies). Would you write d=b, they would point to the same list (of lists). More: Which commands/methods return a deepcopy / shallowcopy / original?
Would b[j] be a nested list instead of a list (e.g., [[1,2,3],[4,5,6]]), its elements would be pointers (references) to the lists on the next level (to the lists [1,2,3] and [4,5,6]). Then copy.copy(b[j]) would produce a copy (c[j]) of that list of pointers. Changing c[j] would then not affect b but changing c[j][k] before that would affect b[j][k].
Using copy.deepcopy instead of copy.copy always makes the result fully independent, as it recursively copies everything (also the nested lists).
As Storyteller wrote, also b depends on a unless you sort a copy of a instead of a:
b = sorted(copy.deepcopy(a), lambda a : a[1]).
Indeed, sorted() produces a shallow copy, so the second level is not copied but pointed to. For non-nested lists, shallow copy is enough for independence.