I know that size_t or ssize_t (signed) will become the type of the return value which comes from the thing we assigning to it
That is not true. These are specific types, and their width is fixed like that of any other type. But the width will be appropriate for your platform (it should be enough to store any address on that platform).
The closest thing to what you describe is C++'s
auto keyword, which deduces the type it should resolve to from the thing you're initialising. But
auto in C means something else (it's a storage specifier) and there is no equivalent mechanism for this kind of type deduction.
I mean, why get trouble when using char, int or etc when size_t can automatically know which data type we should use?
Although this premise is flawed (as discussed above), there's still a good question here: if
size_t is enough to store any address on our system (and
ssize_t is large enough for any pointer difference on that system) then why risk using other types?
Simply put, we may not be storing addresses. Some numbers in our project may need to be bigger; some numbers may always be smaller and so we can save memory. It all comes down to a trade-off between resources and requirements.
If you're thinking that computer memory is usually quite plentiful nowadays, so people might as well just stick to
size_t for all their numbers unless otherwise needed, that's kind of true in many applications, and as such people do tend to stick to those types without giving it much further thought. Unfortunately this habit also leads to unexpected bugs when it's not been planned out carefully enough.
Even if you were using C++'s
auto, it is still debateable as to whether you should just "always use
auto" or not. Sure, it saves you "worrying about it", until you find a bug and need to know what type something actually is. Personally I prefer to be explicit in my code, to tell my computer what I want it to do, but that seems to be a swiftly passing fad.