CMPSC
311,
Spring 2013, Midterm Exam 2, Sample questions for review
Write a code sequence to open a file, read its contents, determine
whether the file contains a line of text longer than 80 characters
(not
including the line-terminating newline character), then print "yes"
or
"no" as appropriate, and close the file. Partial credit for
pseudo-code is possible.
Note that "yes" or "no" should be printed only once. Assume
the
usual Unix text file convention for end-of-line, and ASCII
characters.
Solution
There are many ways to write a correct answer to this problem.
Starting with pseudocode helps in most cases, by concentrating your
attention and reducing disorganization.
Here is an example of a correct answer, although not a full-credit
answer because some of it is still pseudocode.
FILE
*f
= fopen("filename", "r");
// verify f != NULL
char buf[MAXLINE];
// MAXLINE should be
larger than 82, so we can hold the '\n' and '\0'
// from fgets()
int found = 0;
while (fgets(buf, MAXLINE,
f) !=
NULL) {
int n = strlen(buf);
if (n > 81 ||
buf[n] !=
'\n')
{ found =
1;
break; }
}
if (found) printf("yes\n");
else
printf("no\n");
if (fclose(f) != 0)
{ /* error */ }
Assorted mistakes:
- open:
- read from stdin
(instead of opening the file yourself)
- did not check return value of fopen() or open()
- did not save return value of fopen() or open()
- did not state "open for reading"
- read:
- looked at the beginning of the file only
- used getc() or
read() and did
not check for
the beginning of a line
- counted characters in the whole file
- used sizeof
instead of strlen()
- return value of fgets()
is a character count (it's actually a char *)
- print:
- print yes or no for each line of the file, instead of once
only
- close:
- did not check return value of fclose() or close()
- did not close the file
- return vs. exit
- While exit()
causes all open files to be closed, this was supposed to be
just a code
sequence, or maybe a function body, and exit() precludes
later actions.
Explain why this function has a serious bug, or displays a serious
flaw
in the programmer's logic. Its intent is to allocate memory.
char
*
blat(size_t
n)
{
char a[n];
/* assign values to
elements of a[], or maybe not */
return a;
}
Some answers, better to worse
- The storage for a[]
is allocated on the stack, then deallocated when the function
returns. The same storage will be reallocated for the next
function call, so the return value of blat() cannot be used safely.
- Should use malloc()
instead.
- n could be 0,
making
the declaration illegal.
- change the type of n
to int.
- change the return
statement.
Notes
- The definition of a[]
is legal in C99 and C++, though not legal in C89.
(Assuming, of
course, that n is
not 0.)
- size_t is an
unsigned integer type, so n
cannot be negative.
- With regard to the return value, an array name converts to the
address of the first element of the array, so there is no type
mismatch
here.
- Just stating "malloc()
would be better" does not explain why. Also, you would
need to
remind the caller of this function to use free() on the return
value.
- "This does not allocate memory" is wrong; the allocation is on
the stack, but it lasts only until the function returns.
Assorted wrong answers
- operator []
cannot
dynamically allocate memory (confused subscript [] and declarator [], possibly also
confused C89
and C99, or C and C++)
- change the return type
- rearrange the function's spacing (char *blat, for ex.)
- confused n as
number of elements vs. number of bytes, but it's a char array, so same
result (in
other contexts, this would be a valid criticism)
- the array is not initialized (see the comment - doesn't matter
here)
- does not check for "not enough space", could fail (yes, that's
true, but it's up to the runtime system to notice it; there's no
error
indicator for this condition)
Explain why this function has a serious bug, or displays a serious
flaw
in the programmer's logic. Its intent is to allocate and
initialize memory.
void
blat(size_t
n)
{
char *a = malloc(n);
for (int i = 0; i
< n;
i++)
a[i] = 0;
}
Some answers, better to worse
- The local variable a
is the only pointer to the allocated storage, and it is lost on
return
from the function. This causes a memory leak, as there is
no way
to free() the
storage
from outside the function.
- should verify a
!=
NULL before the loop
- it would be easier to call calloc()
Notes
- size_t is an
unsigned integer type, so you don't need to verify 0 <= n.
- Since sizeof(char)
is always 1 in C, changing to malloc(n*sizeof(char))
doesn't fix a bug, although it does make the code more obvious.
Assorted wrong answers
- the comparison i < n
is wrong - the types don't match
- malloc() does not
initialize what it points to (true, but that's why the for loop is there)
- a points to one char, not to an array
(review
the relationship between pointers and arrays)
- did not use malloc(n+1)
(nothing was said about this being a string)
- n is not
initialized
(it is, when the function is called)