Vikram said:
Great thanks for such a clear and detailed explanation! It is a shame C
has picked up all these bad misfeatures from its history. The C-FAQ
section on pointers and arrays is very hard to understand... it would be
much better to have two kinds of pointers: Array Pointers (these would be
pointers returned by malloc and they would be 100% interchangeable with
arrays - in particular sizeof(p) = number of elements in the array) and
General-Purpose Pointers (all other pointers - these would be similar to
arrays according to the current rules (even better, according to
simplified rules) and sizeof(p) would be the number of bytes needed to
store a pointer)
Be careful what you wish for, it might become true;-) You then
would need a whole bag of new syntax if you e.g. want to pass
parts of an array to a function (which is not uncommon). With
C as it is you pass a pointer plus the number of elements that
the function should deal with. But if there would be "array
pointers" how would you propose to convert such a pointer that
points to an array of say 100 elements to one that points to
only 10, starting at the 42nd element? And then, for program-
ming near to the metal, where one often deals with hardware
memory addresses, you would need some syntax to be able to
not only assign an address to the pointer but also how many
bytes/elements in memory should be considered part of the array.
I feel you would end up with a lot of extra, ugly syntax with
not too many real advantages.
But then it's easy to set up your own "counted array pointers".
Instead of using a normal array use a structure like
typedef {
int * data;
size_t len;
} intArray;
Assign what you got from malloc() (or a normal array) to 'data'
and the number of elements to 'len' and pass that to a function
(either directly or as a pointer) and, voila, you've got a
"counted array" at the cost of just a tiny bit of extra typing.
C isn't a large language (and that's one of it's advantages)
but there's nothing that keeps you from creating larger logical
structures out of the elementary building blocks that better
suite your needs.
Of course, feel free to use e.g. C++ instead of C with e.g.
STL vectors - they have exactly the behaviour you're looking
for. Or use some library (the "container library" Jacob Navia
wrote and discussed here quite a number of times in this very
group comes to mind).
Anyway another question: when I submitted my assignment, the teacher said
that instead of my code
scanf("%d",&n);
it is preferable to have an intermediate string-buffer:
scanf("%s",&buf);
n=atoi(buf);
to guard against invalid input. What can go wrong if the user inputs a
non-integer in the first case please?
This is definitely not a good idea. There are several reasons:
a) It's unnecessary - scanf() protects against invalid input.
You just have to check scanf()'s return value, which is the
number of items read in. If it's short of what you expected
there was invalid input. In your case, if scanf() doesn't
return 1 then what the user entered wasn't an integer.
b) You need an extra buffer. How large does it need to be? That's
not a trivial question. It can be hard enough even if you can
expect reasonable input. And it becomes impossible when the
user enters e.g. "0000000000000000000000000000000000001" while
you expect a simple, short number. But that's perfectly valid
input and 'scanf("%d",&n)' deals with it without problems. So,
how long do you need to make the input buffer to cater for all
possible (and valid) cases?
But, even without considering that problem, what your teacher
proposed is very bad (at least if it's exactly as you wrote)
because it might result in a buffer overflow. A format speci-
fier of "%s" doesn't tell scanf() when to stop reading and thus
scanf() will read without regard for how much room there is in
the buffer until it finds a white-space character in the input
- in the process possibly writing past the end of the buffer!
You would at least need something like
scanf( "%99s", buf );
for the case that 'buf' is a char array with 100 elements.
Not telling scanf() how much it is allowed to read into a
char buffer is a very bad mistake. Never ever use a bare
"%s" with scanf() (unless you're absolutely, totally sure
what to expect as input, but even then...).
c) Even if we avoided all those problems using atoi() still is
another thing one should avoid. The problem is that atoi()
(in contrast to scanf()) in no way can tell you if things
worked out as expected. If you passed a buffer to it that
didn't start (after an arbitrary number of white-space cha-
racters) with a number it will return 0, which looks like
reasonable input and gives you no indication that there actu-
ally was a problem. Always use strtol() (for integers) instead.
So, in my opinion, what your teacher proposed is much worse than
what you started with: it makes things a lot more complicated (or
even impossible to get right), it opens up a security hole and
you end up knowing nothing more about the validity of the input.
Regards, Jens