16. Strange Problems

comp.lang.c FAQ list · Question 16.1

Q: Why is this loop always executing once?

	for(i = start; i < end; i++);
		printf("%d\n", i);

A: The accidental extra semicolon hiding at the end of the line containing the for constitutes a null statement which is, as far as the compiler is concerned, the loop body. The following brace-enclosed block, which you thought (and the indentation suggests) was a loop body, is actually the next statement, and it is traversed exactly once, regardless of the number of loop iterations.

See also question 2.18.

References: CT&P Sec. 2.3 pp. 20-21

comp.lang.c FAQ list · Question 16.1b

Q: I'm getting baffling syntax errors which make no sense at all, and it seems like large chunks of my program aren't being compiled.

A: Check for unclosed comments, mismatched #if/#ifdef/#ifndef/#else/#endif directives, and perhaps unclosed quotes; remember to check header files, too. (See also questions 2.18, 10.9, and 11.29a.)

comp.lang.c FAQ list · Question 16.1c

Q: Why isn't my procedure call working? The compiler seems to skip right over it.

A: Does the code look like this?

C has only functions, and function calls always require parenthesized argument lists, even if empty. Use
Without the parentheses, the reference to the function name simply generates a pointer to the function, which is then discarded.

comp.lang.c FAQ list · Question 16.2

Q: I'm getting strange syntax errors on the very first declaration in a file, but it looks fine.

A: See question 10.9.

comp.lang.c FAQ list · Question 16.3

Q: This program crashes before it even runs! (When single-stepping with a debugger, it dies before the first statement in main.)

A: You probably have one or more very large (kilobyte or more) local arrays. Many systems have fixed-size stacks, and even those which perform dynamic stack allocation automatically (e.g. Unix) can be confused when the stack tries to grow by a huge chunk all at once. It is often better to declare large arrays with static duration (unless of course you need a fresh set with each recursive call, in which case you could dynamically allocate them with malloc; see also question 1.31).

Other possibilities are that your program has been linked incorrectly (combining object modules compiled with different compilation options, or using improper dynamic libraries), or that run-time dynamic library linking is failing for some reason, or that you have somehow misdeclared main.

See also questions 11.12b, 16.4, 16.5, and 18.4.

comp.lang.c FAQ list · Question 16.4

Q: I have a program that seems to run correctly, but it crashes as it's exiting, after the last statement in main(). What could be causing this?

A: There are at least three things to look for:

  1. If a semicolon in a previous declaration is missing, main might be inadvertently declared as returning a structure, conflicting with the run-time startup code's expectations. See questions 2.18, 10.9, 11.12b, and 11.14a.
  2. If setbuf or setvbuf is called, and if the supplied buffer is an automatic, local variable of main (or any function), the buffer may not exist any more by the time the stdio library tries to perform its final cleanup.
  3. A cleanup function registered by atexit may have an error. Perhaps it is trying to reference data local to main or to some other function which no longer exists.
(The second and third problems are actually closely related to question 7.5a; see also question 11.16.)

References: CT&P Sec. 5.3 pp. 72-3

comp.lang.c FAQ list · Question 16.5

Q: This program runs perfectly on one machine, but I get weird results on another. Stranger still, adding or removing a debugging printout changes the symptoms...

A: Lots of things could be going wrong; here are a few of the more common things to check:

Proper use of function prototypes can catch several of these problems; lint would catch several more. See also questions 16.3, 16.4, and 18.4.

comp.lang.c FAQ list · Question 16.6

Q: Why does this code:

char *p = "hello, world!";
p[0] = 'H';

A: String constants are in fact constant. The compiler may place them in nonwritable storage, and it is therefore not safe to modify them. When you need writable strings, you must allocate writable memory for them, either by declaring an array, or by calling malloc. Try

	char a[] = "hello, world!";

By the same argument, a typical invocation of the old Unix mktemp routine

	char *tmpfile = mktemp("/tmp/tmpXXXXXX");
is nonportable; the proper usage is
	char tmpfile[] = "/tmp/tmpXXXXXX";

See also question 1.32.

References: ISO Sec. 6.1.4
H&S Sec. 2.7.4 pp. 31-2

comp.lang.c FAQ list · Question 16.7

Q: I've got some code that's trying to unpack external structures, but it's crashing with a message about an ``unaligned access.'' What does this mean? The code looks like this:

struct mystruct {
	char c;
	long int i32;
	int i16;
} s;

char buf[7], *p;
fread(buf, 7, 1, fp);
p = buf;
s.c = *p++;
s.i32 = *(long int *)p;
p += 4;
s.i16 = *(int *)p;

A: The problem is that you're playing too fast and loose with your pointers. Some machines require that data values be stored at appropriately aligned addresses. For instance, two-byte short ints might be constrained to sit at even addresses, and four-byte long ints at multiples of four. (See also question 2.12.) By converting a char * (which can point to any byte) to an int * or long int *, and then indirecting on it, you can end up asking the processor to fetch a multibyte value from an unaligned address, which it isn't willing to do.

A better way to unpack external structures is with code like

	unsigned char *p = buf;

	s.c = *p++;

	s.i32 = (long)*p++ << 24;
	s.i32 |= (long)*p++ << 16;
	s.i32 |= (unsigned)(*p++ << 8);
	s.i32 |= *p++;

	s.i16 = *p++ << 8;
	s.i16 |= *p++;

This code also gives you control over byte order. (This example, though, assumes that a char is 8 bits, and that the long int and int being unpacked from the ``external structure'' are 32 and 16 bits, respectively.) See question 12.42 (which contains some similar code) for a few explanations and caveats.

See also question 4.5.

References: ISO Sec., Sec. 6.3.4
H&S Sec. 6.1.3 pp. 164-5

comp.lang.c FAQ list · Question 16.8

Q: What do ``Segmentation violation'', ``Bus error'', and ``General protection fault'' mean? What's a ``core dump''?

A: These symptoms (and any similar messages having to do with memory access violations or protection faults) generally mean that your program tried to access memory it shouldn't have, invariably as a result of stack corruption or improper pointer use. Likely causes are:

Under Unix, any of these problems almost invariably leads to a ``core dump'': a file named core, [footnote] created in the current directory, containing a memory image of the crashed process, for debugging.

The distinction between ``Bus error'' and ``Segmentation Violation'' may or may not be significant; different versions of Unix generate these signals under different sets of circumstances. Roughly speaking, a segmentation violation indicates an attempt to access memory which doesn't even exist, and a bus error indicates an attempt to access memory in an illegal way (perhaps due to an unaligned pointer; see question 16.7).

See also questions 16.3 and 16.4.

Read sequentially: prev next up

about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North