Null Pointer Assignment Turbo Cars

 

1. Declarations and Initializations

1.1 How should I decide which integer type to use?

1.2 Why aren't the sizes of the standard types precisely defined?

1.3 Since C doesn't define sizes exactly, I've been using typedefs like and . I can then define these typedefs to be , , , etc. depending on what machine I'm using. That should solve everything, right?

1.4 What should the 64-bit type be on a machine that can support it?

1.5 What's wrong with this declaration?

char* p1, p2; I get errors when I try to use .

1.6 I'm trying to declare a pointer and allocate some space for it, but it's not working. What's wrong with this code?

char *p; *p = malloc(10);

1.7 What's the best way to declare and define global variables and functions?

1.8 How can I implement opaque (abstract) data types in C?

1.9 How can I make a sort of ``semi-global'' variable, that is, one that's private to a few functions spread across a few source files?

1.10 Do all declarations for the same function or variable have to include the storage class ?

1.11 What does mean in a function declaration?

1.12 What's the keyword good for?

1.13 What's the difference between using a or a for a user-defined type?

1.14 I can't seem to define a linked list successfully. I tried

typedef struct { char *item; NODEPTR next; } *NODEPTR; but the compiler gave me error messages. Can't a structure in C contain a pointer to itself?

1.15 How can I define a pair of mutually referential structures? I tried

typedef struct { int afield; BPTR bpointer; } *APTR; typedef struct { int bfield; APTR apointer; } *BPTR; but the compiler doesn't know about when it is used in the first structure declaration.

1.16 What's the difference between these two declarations?

struct x1 { ... }; typedef struct { ... } x2;

1.17 What does

typedef int (*funcptr)(); mean?

1.18 I've got the declarations

typedef char *charp; const charp p; Why is turning out , instead of the characters pointed to?

1.19 I don't understand why I can't use values in initializers and array dimensions, as in

const int n = 5; int a[n];

1.20 What's the difference between , , and ?

1.20b

What does it mean for a function parameter to be ? What do the two 's in

int f(const * const p) mean?

1.21 How do I construct declarations of complicated types such as ``array of N pointers to functions returning pointers to functions returning pointers to '', or figure out what similarly complicated declarations mean?

1.22 How can I declare a function that can return a pointer to a function of the same type? I'm building a state machine with one function for each state, each of which returns a pointer to the function for the next state. But I can't find a way to declare the functions--I seem to need a function returning a pointer to a function returning a pointer to a function returning a pointer to a function..., ad infinitum.

1.23 Can I declare a local array (or parameter array) of a size matching a passed-in array, or set by another parameter?

1.24 I have an array which is defined in one file, and used in another:

file1.c:file2.c: int array[] = {1, 2, 3}; extern int array[]; Why doesn't work on in ?

1.25 My compiler is complaining about an invalid redeclaration of a function, but I only define it once and call it once.

1.25b What's the right declaration for ?
Is correct?

1.26 My compiler is complaining about mismatched function prototypes which look fine to me.

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

1.28 My compiler isn't letting me declare a big array like

double array[256][256];

1.29 How can I determine which identifiers are safe for me to use and which are reserved?

1.30 What am I allowed to assume about the initial values of variables and arrays which are not explicitly initialized?
If global variables start out as ``zero'', is that good enough for null pointers and floating-point zeroes?

1.31 This code, straight out of a book, isn't compiling:

int f() { char a[] = "Hello, world!"; }

1.31b What's wrong with this initialization?

char *p = malloc(10); My compiler is complaining about an ``invalid initializer'', or something.

1.32 What is the difference between these initializations?

char a[] = "string literal"; char *p = "string literal"; My program crashes if I try to assign a new value to .

1.33 Is legal?

1.34 I finally figured out the syntax for declaring pointers to functions, but now how do I initialize one?

1.35 Can I initialize unions?


2. Structures, Unions, and Enumerations

2.1 What's the difference between these two declarations?

struct x1 { ... }; typedef struct { ... } x2;

2.2 Why doesn't

struct x { ... }; x thestruct; work?

2.3 Can a structure contain a pointer to itself?

2.4 How can I implement opaque (abstract) data types in C?

2.4b Is there a good way of simulating OOP-style inheritance, or other OOP features, in C?

2.5 Why does the declaration

extern int f(struct x *p); give me an obscure warning message about ``struct x declared inside parameter list''?

2.6 I came across some code that declared a structure like this:

struct name { int namelen; char namestr[1]; }; and then did some tricky allocation to make the array act like it had several elements, with the number recorded by . How does this work? Is it legal or portable?

2.7 I heard that structures could be assigned to variables and passed to and from functions, but K&R1 says not.

2.8 Is there a way to compare structures automatically?

2.9 How are structure passing and returning implemented?

2.10 How can I pass constant values to functions which accept structure arguments? How can I create nameless, immediate, constant structure values?

2.11 How can I read/write structures from/to data files?

2.12 Why is my compiler leaving holes in structures, wasting space and preventing ``binary'' I/O to external data files? Can I turn this off, or otherwise control the alignment of structure fields?

2.13 Why does report a larger size than I expect for a structure type, as if there were padding at the end?

2.14 How can I determine the byte offset of a field within a structure?

2.15 How can I access structure fields by name at run time?

2.16 Does C have an equivalent to Pascal's statement?

2.17 If an array name acts like a pointer to the base of an array, why isn't the same thing true of a structure?

2.18 This program works correctly, but it dumps core after it finishes. Why?

struct list { char *item; struct list *next; } /* Here is the main program. */ main(argc, argv) { ... }

2.19 What's the difference between a structure and a union, anyway?

2.20 Can I initialize unions?

2.21 Is there an automatic way to keep track of which field of a union is in use?

2.22 What's the difference between an enumeration and a set of preprocessor s?

2.23 Are enumerations really portable?
Aren't they Pascalish?

2.24 Is there an easy way to print enumeration values symbolically?

2.25 I came across some structure declarations with colons and numbers next to certain fields, like this:

struct record { char *name; int refcount : 4; unsigned dirty : 1; }; What gives?

2.26 Why do people use explicit masks and bit-twiddling code so much, instead of declaring bit-fields?


3. Expressions

3.1 Why doesn't this code:

a[i] = i++; work?

3.2 Under my compiler, the code

int i = 7; printf("%d\n", i++ * i++); prints 49. Regardless of the order of evaluation, shouldn't it print 56?

3.3 I've experimented with the code

int i = 3; i = i++; on several compilers. Some gave the value 3, and some gave 4. Which compiler is correct?

3.3b Here's a slick expression:

a ^= b ^= a ^= b It swaps and without using a temporary.

3.4 Can I use explicit parentheses to force the order of evaluation I want, and control these side effects? Even if I don't, doesn't precedence dictate it?

3.5 But what about the and operators?
I see code like ``'' ...

3.6 Is it safe to assume that the right-hand side of the and operators won't be evaluated if the left-hand side determines the outcome?

3.7 Why did

printf("%d %d", f1(), f2()); call first? I thought the comma operator guaranteed left-to-right evaluation.

3.8 How can I understand complex expressions like the ones in this section, and avoid writing undefined ones? What's a ``sequence point''?

3.9 So if I write

a[i] = i++; and I don't care which cell of gets written to, the code is fine, and gets incremented by one, right?

3.10a People keep saying that the behavior of is undefined, but I just tried it on an ANSI-conforming compiler, and got the results I expected.

3.10b People told me that if I evaluated an undefined expression, or accessed an uninitialized variable, I'd get a random, garbage value. But I tried it, and got zero. What's up with that?

3.11 How can I avoid these undefined evaluation order difficulties if I don't feel like learning the complicated rules?

3.12a What's the difference between and ?

3.12b If I'm not using the value of the expression, should I use or to increment a variable?

3.13 I need to check whether one number lies between two others. Why doesn't

if(a < b < c) work?

3.14 Why doesn't the code

int a = 1000, b = 1000; long int c = a * b; work?

3.14b How can I ensure that integer arithmetic doesn't overflow?

3.15 Why does the code

double degC, degF; degC = 5 / 9 * (degF - 32); keep giving me 0?

3.16 I have a complicated expression which I have to assign to one of two variables, depending on a condition. Can I use code like this?

((condition) ? a : b) = complicated_expression;

3.17 I have some code containing expressions like

a ? b = c : d and some compilers are accepting it but some are not.

3.18 What does the warning ``semantics of `' change in ANSI C'' mean?

3.19 What's the difference between the ``unsigned preserving'' and ``value preserving'' rules?


4. Pointers

4.1 What are pointers really good for, anyway?

4.2 I'm trying to declare a pointer and allocate some space for it, but it's not working. What's wrong with this code?

char *p; *p = malloc(10);

4.3 Does increment , or what it points to?

4.4 I'm trying to use pointers to manipulate an array of s. What's wrong with this code?

int array[5], i, *ip; for(i = 0; i < 5; i++) array[i] = i; ip = array; printf("%d\n", *(ip + 3 * sizeof(int))); I expected the last line to print 3, but it printed garbage.

4.5 I have a pointer that happens to point to some s, and I want to step it over them. Why doesn't

((int *)p)++; work?

4.6 Why can't I perform arithmetic on a pointer?

4.7 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?

4.8 I have a function which accepts, and is supposed to initialize, a pointer:

void f(int *ip) { static int dummy = 5; ip = &dummy; } But when I call it like this: int *ip; f(ip); the pointer in the caller remains unchanged.

4.9 Suppose I want to write a function that takes a generic pointer as an argument and I want to simulate passing it by reference. Can I give the formal parameter type , and do something like this?

void f(void **); double *dp; f((void **)&dp);

4.10 I have a function

extern int f(int *); which accepts a pointer to an . How can I pass a constant by reference? A call like f(&5); doesn't seem to work.

4.11 Does C even have ``pass by reference''?

4.12 I've seen different syntax used for calling functions via pointers. What's the story?

4.13 What's the total generic pointer type? My compiler complained when I tried to stuff function pointers into a .

4.14 How are integers converted to and from pointers? Can I temporarily stuff an integer into a pointer, or vice versa?

4.15 How do I convert an to a ? I tried a cast, but it's not working.

4.16 What's wrong with this declaration?

char* p1, p2; I get errors when I try to use .

4.17 What are ``near'' and ``far'' pointers?


5. Null Pointers

5.1 What is this infamous null pointer, anyway?

5.2 How do I get a null pointer in my programs?

5.3 Is the abbreviated pointer comparison ``'' to test for non-null pointers valid? What if the internal representation for null pointers is nonzero?

5.4 What is and how is it defined?

5.5 How should be defined on a machine which uses a nonzero bit pattern as the internal representation of a null pointer?

5.6 If were defined as follows:

#define NULL ((char *)0) wouldn't that make function calls which pass an uncast work?

5.7 My vendor provides header files that as . Why?

5.8 Is valid for pointers to functions?

5.9 If and are equivalent as null pointer constants, which should I use?

5.10 But wouldn't it be better to use (rather than ), in case the value of changes, perhaps on a machine with nonzero internal null pointers?

5.11 I once used a compiler that wouldn't work unless was used.

5.12 I use the preprocessor macro

#define Nullptr(type) (type *)0 to help me build null pointers of the correct type.

5.13 This is strange. is guaranteed to be , but the null pointer is not?

5.14 Why is there so much confusion surrounding null pointers? Why do these questions come up so often?

5.15 I'm confused. I just can't understand all this null pointer stuff.

5.16 Given all the confusion surrounding null pointers, wouldn't it be easier simply to require them to be represented internally by zeroes?

5.17 Seriously, have any actual machines really used nonzero null pointers, or different representations for pointers to different types?

5.18 Is a run-time integral value of 0, cast to a pointer, guaranteed to be a null pointer?

5.19 How can I access an interrupt vector located at the machine's location 0? If I set a pointer to , the compiler might translate it to some nonzero internal null pointer value.

5.20 What does a run-time ``null pointer assignment'' error mean? How can I track it down?


6. Arrays and Pointers

6.1 I had the definition in one source file, and in another I declared . Why didn't it work?

6.2 But I heard that was identical to .

6.3 So what is meant by the ``equivalence of pointers and arrays'' in C?

6.4 If they're so different, then why are array and pointer declarations interchangeable as function formal parameters?

6.4b So arrays are passed by reference, even though the rest of C uses pass by value?

6.5 Why can't I do something like this?

extern char *getpass(); char str[10]; str = getpass("Enter password: ");

6.6 If you can't assign to arrays, then how can

int f(char str[]) { if(str[0] == '\0') str = "none"; ... } work?

6.6b And what about this? Isn't this an array assignment?

char a[] = "Hello, world!\n";

6.7 How can an array be an lvalue, if you can't assign to it?

6.8 Practically speaking, what is the difference between arrays and pointers?

6.9 Someone explained to me that arrays were really just constant pointers.

6.10 I'm still mystified. Is a pointer a kind of array, or is an array a kind of pointer?

6.11 I came across some ``joke'' code containing the ``expression'' . How can this be legal C?

6.12 Since array references decay into pointers, if is an array, what's the difference between and ?

6.13 How do I declare a pointer to an array?

6.14 How can I set an array's size at run time?
How can I avoid fixed-sized arrays?

6.15 How can I declare local arrays of a size matching a passed-in array?

6.16 How can I dynamically allocate a multidimensional array?

6.17 Here's a neat trick: if I write

int realarray[10]; int *array = &realarray[-1]; I can treat as if it were a 1-based array.

6.18 My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer.

6.19 How do I write functions which accept two-dimensional arrays when the width is not known at compile time?

6.20 How can I use statically- and dynamically-allocated multidimensional arrays interchangeably when passing them to functions?

6.21 Why doesn't properly report the size of an array when the array is a parameter to a function? I have a test routine

f(char a[10]) { int i = sizeof(a); printf("%d\n", i); } and it prints 4, not 10.

6.22 How can code in a file where an array is declared as (i.e. it is defined, and its size determined, in some other file) determine the size of the array? doesn't seem to work.

6.23 I want to know how many elements are in an array, but yields the size in bytes.

6.24 Is there a way to have an array of bits?


7. Memory Allocation

7.1 Why doesn't this fragment work?

char *answer; printf("Type something:\n"); gets(answer); printf("You typed \"%s\"\n", answer);

7.2 I can't get to work. I tried

char *s1 = "Hello, "; char *s2 = "world!"; char *s3 = strcat(s1, s2); but I got strange results.

7.3 But the man page for says that it takes two 's as arguments. How am I supposed to know to allocate things?

7.3b I just tried the code

char *p; strcpy(p, "abc"); and it worked. How? Why didn't it crash?

7.3c How much memory does a pointer variable allocate?

7.4 I'm reading lines from a file into an array, with this code:

char linebuf[80]; char *lines[100]; int i; for(i = 0; i < 100; i++) { char *p = fgets(linebuf, 80, fp); if(p == NULL) break; lines[i] = p; } Why do all the lines end up containing copies of the last line?

7.5a I have a function that is supposed to return a string, but when it returns to its caller, the returned string is garbage.

7.5b So what's the right way to return a string or other aggregate?

7.6 Why am I getting ``warning: assignment of pointer from integer lacks a cast'' for calls to ?

7.7 Why does some code carefully cast the values returned by to the pointer type being allocated?

7.7b What's wrong with casting 's return value?

7.7c In a call to , what does an error like ``Cannot convert `' to `

7.8 I see code like

char *p = malloc(strlen(s) + 1); strcpy(p, s); Shouldn't that be ?

7.9 I wrote a little wrapper around , but it doesn't work:

#include <stdio.h> #include <stdlib.h> mymalloc(void *retp, size_t size) { retp = malloc(size); if(retp == NULL) { fprintf(stderr, "out of memory\n"); exit(EXIT_FAILURE); } }

7.10 I'm trying to declare a pointer and allocate some space for it, but it's not working. What's wrong with this code?

char *p; *p = malloc(10);

7.10a What's wrong with this initialization?

char *p = malloc(10); My compiler is complaining about an ``invalid initializer'', or something.

7.10b How can I shut off the ``warning: possible pointer alignment problem'' message which gives me for each call to ?

7.11 How can I dynamically allocate arrays?

7.12 How can I find out how much memory is available?

7.13 What should do? Return a null pointer or a pointer to 0 bytes?

7.14 I've heard that some operating systems don't actually allocate 'ed memory until the program tries to use it. Is this legal?

7.15 is returning crazy pointer values, but I did read question 7.6 and I have included the line

extern void *malloc(); before I call it.

7.16 I'm allocating a large array for some numeric work, using the line

double *array = malloc(300 * 300 * sizeof(double)); isn't returning null, but the program is acting strangely, as if it's overwriting memory, or isn't allocating as much as I asked for, or something.

7.17 I've got 8 meg of memory in my PC. Why can I only seem to 640K or so?

7.18 My application depends heavily on dynamic allocation of nodes for data structures, and / overhead is becoming a bottleneck. What can I do?

7.19 My program is crashing, apparently somewhere down inside , but I can't see anything wrong with it. Is there a bug in ?

7.19b

I'm dynamically allocating an array, like this:

int *iarray = (int *)malloc(nints); isn't returning NULL, but the code isn't working.

7.20 You can't use dynamically-allocated memory after you free it, can you?

7.21 Why isn't a pointer null after calling ?
How unsafe is it to use (assign, compare) a pointer value after it's been freed?

7.22 When I call to allocate memory for a pointer which is local to a function, do I have to explicitly it?

7.23 I'm allocating structures which contain pointers to other dynamically-allocated objects. When I free a structure, do I also have to free each subsidiary pointer?

7.24 Must I free allocated memory before the program exits?

7.25 I have a program which s and later s a lot of memory, but I can see from the operating system that memory usage doesn't actually go back down.

7.26 How does know how many bytes to free?

7.27 So can I query the malloc package to find out how big an allocated block is?

7.28 Why doesn't tell me the size of the block of memory pointed to by a pointer?

7.29 Having dynamically allocated an array (as in question 6.14), can I change its size?

7.30 Is it legal to pass a null pointer as the first argument to ? Why would you want to?

7.31 What's the difference between and ? Which should I use? Is it safe to take advantage of 's zero-filling? Does work on memory allocated with , or do you need a ?

7.32 What is and why is its use discouraged?


8. Characters and Strings

8.1 Why doesn't

strcat(string, '!'); work?

8.2 I'm checking a string to see if it matches a particular value. Why isn't this code working?

char *string; ... if(string == "value") { /* string matches "value" */ ... }

8.3 If I can say

char a[] = "Hello, world!"; why can't I say char a[14]; a = "Hello, world!";

8.4 I can't get to work. I tried

char *s1 = "Hello, "; char *s2 = "world!"; char *s3 = strcat(s1, s2); but I got strange results.

8.5 What is the difference between these initializations?

char a[] = "string literal"; char *p = "string literal"; My program crashes if I try to assign a new value to .

8.6 How can I get the numeric value (i.e. ASCII or other character set code) corresponding to a character, or vice versa?

8.7 Does C have anything like the ``substr'' (extract substring) routine present in other languages?

8.8 I'm reading strings typed by the user into an array, and then printing them out later. When the user types a sequence like , why isn't it being handled properly?

8.9 I think something's wrong with my compiler: I just noticed that is 2, not 1 (i.e. not ).

8.10 I'm starting to think about multinational character sets, and I'm worried about the implications of making be 2 so that 16-bit character sets can be represented.


9. Boolean Expressions and Variables

9.1 What is the right type to use for Boolean values in C? Is there a standard type? Should I use s or enums for the true and false values?

9.2 Isn't #defining to be 1 dangerous, since any nonzero value is considered ``true'' in C? What if a built-in logical or relational operator ``returns'' something other than 1?

9.3 Is , where is a pointer, a valid and portable test?

9.4 Should I use symbolic names like and for Boolean constants, or plain 1 and 0?

9.5 A third-party header file I just started using is defining its own and values incompatibly with the code I've already developed. What can I do?


10. C Preprocessor

10.1 I'm trying to define a few simple little function-like macros such as

#define square(x) x * x but they're not always working.

10.2 Here are some cute preprocessor macros:

#define begin { #define end } With these, I can write C code that looks more like Pascal. What do y'all think?

10.3 How can I write a generic macro to swap two values?

10.4 What's the best way to write a multi-statement macro?

10.5 What's the difference between using a or a for a user-defined type?

10.5b What's the difference between

const MAXSIZE = 100; and #define MAXSIZE 100

10.6 I'm splitting up a program into multiple source files for the first time, and I'm wondering what to put in files and what to put in files. (What does ``'' mean, anyway?)

10.7 Is it acceptable for one header file to another?

10.8a What's the difference between and ?

10.8b What are the complete rules for header file searching?

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

10.10 I'm using header files which accompany two different third-party libraries, and they are ``helpfully'' defining common macros such as , , , and , but the definitions clash with each other and with definitions I'd already established in my own header files. What can I do?

10.10b I'm #including the right header file for the library function I'm using, but the linker keeps saying it's undefined.

10.11 I'm compiling a program, and I seem to be missing one of the header files it requires. Can someone send me a copy?

10.12 How can I construct preprocessor expressions which compare strings?

10.13 Does the operator work in preprocessor directives?

10.14 Can I use an in a line, to define something two different ways, like this?

#define a b \ #ifdef whatever c d #else e f g #endif

10.15 Is there anything like an for s?

10.16 How can I use a preprocessor expression to tell whether a machine's byte order is big-endian or little-endian?

10.17 I'm getting strange syntax errors inside lines I've fed out.

10.18 I inherited some code which contains far too many 's for my taste. How can I preprocess the code to leave only one conditional compilation set, without running it through the preprocessor and expanding all of the 's and 's as well?

10.19 How can I list all of the predefined identifiers?

10.20 I have some old code that tries to construct identifiers with a macro like

#define Paste(a, b) a/**/b but it doesn't work any more.

10.21 I have an old macro

#define CTRL(c) ('c' & 037) that doesn't seem to work any more.

10.22 Why is the macro

#define TRACE(n) printf("TRACE: %d\n", n) giving me the warning ``macro replacement within a string literal''? It seems to be expanding TRACE(count); as printf("TRACE: %d\count", count);

10.23 How can I use a macro argument inside a string literal in the macro expansion?

10.24 I'm trying to use the ANSI ``stringizing'' preprocessing operator `' to insert the value of a symbolic constant into a message, but it keeps stringizing the macro's name rather than its value.

10.25 I've got this tricky preprocessing I want to do and I can't figure out a way to do it.

10.26 How can I write a macro which takes a variable number of arguments, or use the preprocessor to ``turn off'' a function call with a variable number of arguments?

10.27 How can I include expansions of the and macros in a general-purpose debugging macro?


11. ANSI/ISO Standard C

11.1 What is the ``ANSI C Standard?''

11.2 How can I get a copy of the Standard?

11.2b Where can I get information about updates to the Standard?

11.3 My ANSI compiler complains about a mismatch when it sees

extern int func(float); int func(x) float x; { ...

11.4 Can you mix old-style and new-style function syntax?

11.5 Why does the declaration

extern int f(struct x *p); give me an obscure warning message about ``struct x declared inside parameter list''?

11.6 I had a frustrating problem which turned out to be caused by the line

printf("%d", n); where was actually a . I thought that ANSI function prototypes were supposed to guard against argument type mismatches like this.

11.7 I heard that you have to before calling . Why?

11.8 I don't understand why I can't use values in initializers and array dimensions, as in

const int n = 5; int a[n];

11.8b If you can't modify string literals, why aren't they defined as being arrays of characters?

11.9 What's the difference between , , and ?

11.10 Why can't I pass a to a function which expects a ?

11.11 I've got the declarations

typedef char *charp; const charp p; Why is turning out , instead of the characters pointed to?

11.11b What's the difference between

const MAXSIZE = 100; and #define MAXSIZE 100

11.12a What's the correct declaration of ?

11.12b Can I declare as , to shut off these annoying ``main returns no value'' messages?

11.13 But what about 's third argument, ?

11.14a I believe that declaring can't fail, since I'm calling instead of returning, and anyway my operating system ignores a program's exit/return status.

11.14b So what could go wrong? Are there really any systems where doesn't work?

11.15 The book I've been using, C Programing for the Compleat Idiot, always uses .

11.16 Is truly equivalent to returning the same from ?

11.17 I'm trying to use the ANSI ``stringizing'' preprocessing operator `' to insert the value of a symbolic constant into a message, but it keeps stringizing the macro's name rather than its value.

11.18 What does the message ``warning: macro replacement within a string literal'' mean?

11.19 I'm getting strange syntax errors inside lines I've fed out.

11.20 What are s and what are they good for?

11.21 What does ``'' mean? I found it in some header files.

11.22 Is legal? What does it mean?

11.23 Since array references decay into pointers, if is an array, what's the difference between and ?

11.24 Why can't I perform arithmetic on a pointer?

11.25 What's the difference between and ?

11.26 What should do? Return a null pointer or a pointer to 0 bytes?

11.27 Why does the ANSI Standard place limits on the length and case-significance of external identifiers?

11.28 What was and what ever happened to it?

11.29a My compiler is rejecting the simplest possible test programs, with all kinds of syntax errors. It's complaining about the first line of

main(int argc, char **argv) { return 0; }

11.29b What does the message ``Automatic aggregate intialization is an ANSI feature'' mean? My compiler is complaining about valid ANSI code.

11.30 Why are some ANSI/ISO Standard library functions showing up as undefined, even though I've got an ANSI compiler?

11.31 Does anyone have a tool for converting old-style C programs to ANSI C, or vice versa, or for automatically generating prototypes?

11.32 Why won't the Frobozz Magic C Compiler, which claims to be ANSI compliant, accept this code? I know that the code is ANSI, because accepts it.

11.33 People seem to make a point of distinguishing between implementation-defined, unspecified, and undefined behavior. What do these mean?

11.33b What does it really mean for a program to be ``legal'' or ``valid'' or ``conforming''?

11.34 I'm appalled that the ANSI Standard leaves so many issues undefined. Isn't a Standard's whole job to standardize these things?

11.35 People keep saying that the behavior of is undefined, but I just tried it on an ANSI-conforming compiler, and got the results I expected.


12. Stdio

12.1 What's wrong with this code?

char c; while((c = getchar()) != EOF) ...

12.1b I have a simple little program that reads characters until EOF, but how do I actually enter that ``EOF'' value from the keyboard? I see that is defined by to be -1; am I supposed to enter -1?

12.2 Why does the simple line-copying loop copy the last line twice?

12.3 I'm using to read lines from a file into an array of pointers. Why do all the lines end up containing copies of the last line?

12.4 My program's prompts and intermediate output don't always show up on the screen, especially when I pipe the output through another program.

12.5 How can I read one character at a time, without waiting for the RETURN key?

12.6 How can I print a character in a format string? I tried , but it didn't work.

12.7 Why doesn't

long int n = 123456; printf("%d\n", n); work?

12.8 I thought that ANSI function prototypes were supposed to guard against argument type mismatches.

12.9 Someone told me it was wrong to use with . How can use for type , if requires ?

12.9b What format should I use for a typedef like when I don't know whether it's or some other type?

12.10 How can I implement a variable field width with ? That is, instead of something like , I want the width to be specified at run time.

12.11 How can I print numbers with commas separating the thousands?
What about currency formatted numbers?

12.12 Why doesn't the call work?

12.12b Why does the call

char s[30]; scanf("%s", s); work? I thought you always needed an on each variable passed to .

12.13 Why doesn't this code:

double d; scanf("%f", &d); work?

12.14 Why doesn't the code

short int s; scanf("%d", &s); work?

12.15 How can I specify a variable width in a format string?

12.16 How can I read data from data files with particular formats?
How can I read ten floats without having to use a jawbreaker format
like ?
How can I read an arbitrary number of fields from a line into an array?

12.17 When I read numbers from the keyboard with and a format, like this:

int n; scanf("%d\n", &n); printf("you typed %d\n", n); it seems to hang until I type one extra line of input.

12.18a I'm reading a number with and , and then a string with :

int n; char str[80]; printf("enter a number: "); scanf("%d", &n); printf("enter a string: "); gets(str); printf("you typed %d and \"%s\"\n", n, str); but the compiler seems to be skipping the call to !

12.18b I'm using to read a Y/N response, but later input gets skipped.

12.19 I figured I could use more safely if I checked its return value to make sure that the user typed the numeric values I expect:

int n; while(1) { printf("enter a number: "); if(scanf("%d", &n) == 1) break; printf("try again: "); } printf("you typed %d\n", n); but sometimes it seems to go into an infinite loop. [footnote] Why?

12.20 Why does everyone say not to use ? What should I use instead?

12.21 How can I tell how much destination buffer space I'll need for an arbitrary call? How can I avoid overflowing the destination buffer with ?

12.22 What's the deal on 's return value? Is it an or a ?

12.23 Why does everyone say not to use ?

12.24 I thought I'd check after a long string of calls, to see if any of them had failed:

errno = 0; printf("This\n"); printf("is\n"); printf("a\n"); printf("test.\n"); if(errno != 0) fprintf(stderr, "printf failed: %s\n", strerror(errno)); Why is it printing something strange like ``printf failed: Not a typewriter'' when I redirect the output to a file?

12.25 What's the difference between / and /?
What are and good for?

12.26a How can I flush pending input so that a user's typeahead isn't read at the next prompt? Will work?

12.26b If won't work, what can I use to flush input?

12.27 I wrote this routine which is supposed to open a file:

myfopen(char *filename, FILE *fp) { fp = fopen(filename, "r"); } But when I call it like this: FILE *infp; myfopen("filename.dat", infp); the variable in the caller doesn't get set properly.

12.28 I can't even get a simple call to work! What's wrong with this call?

FILE *fp = fopen(filename, 'r');

12.28b How can I open files with names like ``'', ``'', ``'', etc., where the numeric part is controlled by a variable? Basically I want ``'', like .

12.29 is failing for certain pathnames.

12.30 I'm trying to update a file in place, by using mode , reading a certain string, and writing back a modified string, but it's not working.

12.31 How can I insert or delete a line (or record) in the middle of a file?

12.32 How can I recover the file name given an open stream?

12.33 How can I redirect or to a file from within a program?

12.34 Once I've used , how can I get the original (or ) back?

12.35 How can I tell if standard input or output is redirected (i.e. whether ``'' or ``'' was used on the invocation command line)?

12.36 I'm trying to write a program like ``.'' How can I get back to the interactive keyboard if is redirected?

12.36b How can I arrange to have output go two places at once, e.g. to the screen and to a file?

12.37 I want to read and write numbers between files and memory in a byte-at-a-time way, not as formatted characters the way and do. How can I do this?

12.38 How can I read a binary data file properly? I'm occasionally seeing and values getting garbled, and I seem to hit EOF prematurely if the data contains the value .

12.39 I'm writing a ``filter'' for binary files, but and are preopened as text streams. How can I change their mode to binary?

12.40 What's the difference between text and binary I/O?

12.41 How can I read/write structures from/to data files?

12.42 How can I write code to conform to these old, binary data file formats?

12.43 I'm reading strings typed by the user into an array, and then printing them out later. When the user types a sequence like , why isn't it being handled properly?


13. Library Functions

13.1 How can I convert numbers to strings (the opposite of )? Is there an function?

13.2 Why does not always place a terminator in the destination string?

13.3 Does C have anything like the ``substr'' (extract substring) routine present in other languages?

13.4 How do I convert a string to all upper or lower case?

13.5 Why do some versions of act strangely if given an upper-case letter?
Why does some code call before ?

13.6 How can I split up a string into whitespace-separated fields?
How can I duplicate the process by which is handed and ?

13.7 I need some code to do regular expression and wildcard matching.

13.8 I'm trying to sort an array of strings with , using as the comparison function, but it's not working.

13.9 Now I'm trying to sort an array of structures with . My comparison function takes pointers to structures, but the compiler complains that the function is of the wrong type for . How can I cast the function pointer to shut off the warning?

13.10 How can I sort a linked list?

13.11 How can I sort more data than will fit in memory?

13.12 How can I get the current date or time of day in a C program?

13.13 I know that the library function will convert a into a broken-down , and that will convert a to a printable string. How can I perform the inverse operations of converting a or a string into a ?

13.14 How can I add N days to a date? How can I find the difference between two dates?

13.14b Did C have any Year 2000 problems?

13.15 I need a random number generator.

13.16 How can I get random integers in a certain range?

13.17 Each time I run my program, I get the same sequence of numbers back from .

13.18 I need a random true/false value, so I'm just taking , but it's alternating 0, 1, 0, 1, 0...

13.19 How can I return a sequence of random numbers which don't repeat at all?

13.19b How can I generate floating-point random numbers?

13.20 How can I generate random numbers with a normal or Gaussian distribution?

13.21 I'm porting this program, and it calls a routine , which my library doesn't have. What is it?

13.22 Is truly equivalent to returning the same from ?

13.23 What's the difference between and ?

13.24 I'm trying to port this old program. Why do I get ``undefined external'' errors for some library functions?

13.25 I keep getting errors due to library functions being undefined, but I'm #including all the right header files.

13.26 I'm still getting errors due to library functions being undefined, even though I'm explicitly requesting the right libraries while linking.

13.27 Why is my simple program, which hardly does more than print ``Hello, world!'' in a window, compiling to such a huge executable (several hundred K)? Should I fewer header files?

13.28 What does it mean when the linker says that is undefined?

13.29 My compiler is complaining that is undefined! How can this be? It's the world's most popular C function...


14. Floating Point

14.1 When I set a variable to, say, 3.1, why is printing it as 3.0999999?

14.2 I'm trying to take some square roots, and I've simplified the code down to

main() { printf("%f\n", sqrt(144.)); } but I'm still getting crazy numbers.

14.3 I'm trying to do some simple trig, and I am #including , but the linker keeps complaining that functions like and are undefined.

14.4a My floating-point calculations are acting strangely and giving me different answers on different machines.

14.4b I'm sure I've got the trig functions declared correctly, but they're still giving me wrong answers.

14.5 What's a good way to check for ``close enough'' floating-point equality?

14.6 How do I round numbers?

14.7 Why doesn't C have an exponentiation operator?

14.8 The predefined constant seems to be missing from my machine's copy of .

14.9 How do I set variables to, or test for IEEE NaN (``Not a Number'') and other special values?

14.10 How can I handle floating-point exceptions gracefully?

14.11 What's a good way to implement complex numbers in C?

14.12 I'm looking for some code to do:

Fast Fourier Transforms (FFT's)
matrix arithmetic (multiplication, inversion, etc.)
complex arithmetic

14.13 I'm having trouble with a Turbo C program which crashes and says something like ``floating point formats not linked.''


15. Variable-Length Argument Lists

15.1 I heard that you have to before calling . Why?

15.2 How can be used for both and arguments in ? Aren't they different types?

15.3 I had a frustrating problem which turned out to be caused by the line

printf("%d", n); where was actually a . I thought that ANSI function prototypes were supposed to guard against argument type mismatches like this.

15.4 How can I write a function that takes a variable number of arguments?

15.5 How can I write a function that takes a format string and a variable number of arguments, like , and passes them to to do most of the work?

15.6 How can I write a function analogous to , i.e. that accepts similar arguments, and calls to do most of the work?

15.7 I have a pre-ANSI compiler, without . What can I do?

15.8 How can I discover how many arguments a function was actually called with?

15.9 My compiler isn't letting me declare a function

int f(...) { } i.e. accepting a variable number of arguments, but with no fixed arguments at all.

15.10 I have a varargs function which accepts a parameter. Why isn't

va_arg(argp, float) working?

15.11 I can't get to pull in an argument of type pointer-to-function.

15.12 How can I write a function which takes a variable number of arguments and passes them to some other function (which takes a variable number of arguments)?

15.13 How can I call a function with an argument list built up at run time?


16. Strange Problems

16.1 Why is this loop always executing once?

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

16.1b 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.

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

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

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

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

16.5 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...

16.6 Why does this code:

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

16.7

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;

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


17. Style

17.1 What's the best style for code layout in C?

17.2 How should functions be apportioned among source files?

17.3 Here's a neat trick for checking whether two strings are equal:

if(!strcmp(s1, s2)) Is this good style?

17.4 Why do some people write instead of ?

17.4b I've seen function declarations that look like this:

extern int func __((int, int)); What are those extra parentheses and underscores for?

17.5 I came across some code that puts a cast before each call to . Why?

17.6 If and are equivalent as null pointer constants, which should I use?

17.7 Should I use symbolic names like and for Boolean constants, or plain 1 and 0?

17.8 What is ``Hungarian Notation''? Is it worthwhile?

17.9 Where can I get the ``Indian Hill Style Guide'' and other coding standards?

17.10 Some people say that 's are evil and that I should never use them. Isn't that a bit extreme?

17.11 People always say that good style is important, but when they go out of their way to use clear techniques and make their programs readable, they seem to end up with less efficient programs. Since efficiency is so important, isn't it necessary to sacrifice some style and readability?

17.12 Which is correct,

char *p or char* p ?

18. Tools and Resources

18.1 I need some C development tools.

18.2 How can I track down these pesky malloc problems?

18.3 What's a free or cheap C compiler I can use?

18.4 I just typed in this program, and it's acting strangely. Can you see anything wrong with it?

18.5 How can I shut off the ``warning: possible pointer alignment problem'' message which gives me for each call to ?

18.6 Can I declare as , to shut off these annoying ``main returns no value'' messages?

18.7 Where can I get an ANSI-compatible ?

18.8 Don't ANSI function prototypes render obsolete?

18.9 Are there any C tutorials or other resources on the net?

18.9b Where can I find some good code examples to study and learn from?

18.10 What's a good book for learning C? What about advanced books and references?

18.11 Where can I find answers to the exercises in K&R?

18.12 Does anyone know where the source code from books like Numerical Recipes in C, Plauger's The Standard C Library, or Kernighan and Pike's The UNIX Programming Environment is available on-line?

18.13 Where can I find the sources of the standard C libraries?

18.13b Is there an on-line C reference manual?

18.13c Where can I get a copy of the ANSI/ISO C Standard?

18.14 I need code to parse and evaluate expressions.

18.15 Where can I get a BNF or YACC grammar for C?

18.15b Does anyone have a C compiler test suite I can use?

18.15c Where are some collections of useful code fragments and examples?

18.15d I need code for performing multiple precision arithmetic.

18.16 Where and how can I get copies of all these freely distributable programs?

18.17 Where can I get extra copies of this list?


19. System Dependencies

19.1 How can I read a single character from the keyboard without waiting for the RETURN key? How can I stop characters from being echoed on the screen as they're typed?

19.2 How can I find out if there are characters available for reading (and if so, how many)? Alternatively, how can I do a read that will not block if there are no characters available?

19.3 How can I display a percentage-done indication that updates itself in place, or show one of those ``twirling baton'' progress indicators?

19.4 How can I clear the screen?
How can I print text in color?
How can I move the cursor to a specific x, y position?

19.4b I'm compiling some test programs on a windows-based system, and the windows containing my program's output are closing so quickly after my program calls that I can't see the output. How can I make it pause before closing?

19.5 How do I read the arrow keys? What about function keys?

19.6 How do I read the mouse?

19.7 How can I do serial (``comm'') port I/O?

19.8 How can I direct output to the printer?

19.9 How do I send escape sequences to control a terminal or other device?

19.9b How can I access an I/O board directly?

19.10 How can I do graphics?

19.10b How can I display GIF and JPEG images?

19.10c How can I load new fonts for display?

19.10d How can I send mail from within a C program?

19.11 How can I check whether a file exists? I want to warn the user if a requested input file is missing.

19.12 How can I find out the size of a file, prior to reading it in?

19.12b How can I find the modification date and time of a file?

19.13 How can a file be shortened in-place without completely clearing or rewriting it?

19.14 How can I insert or delete a line (or record) in the middle of a file?

19.15 How can I recover the file name given an open stream or file descriptor?

19.16 How can I delete a file?

19.16b How do I copy files?

19.17 Why can't I open a file by its explicit path? The call

fopen("c:\newdir\file.dat", "r") is failing.

19.17b isn't letting me open files like and .

19.17c How can I suppress the dreaded MS-DOS ``Abort, Retry, Ignore?'' message?

19.18 I'm getting an error, ``Too many open files''. How can I increase the allowable number of simultaneously open files?

19.19 How can I find out how much free space is available on disk?

19.20 How can I read a directory in a C program?

19.21 How do I create a directory?
How do I remove a directory (and its contents)?

19.22 How can I find out how much memory is available?

19.23 How can I allocate arrays or structures bigger than 64K?

19.24 What does the error message ``DGROUP data allocation exceeds 64K'' mean, and what can I do about it? I thought that using large model meant that I could use more than 64K of data!

19.25 How can I access memory (a memory-mapped device, or graphics memory) located at a certain address?
How can I do PEEK and POKE in C?

19.25b How can I determine whether a machine's byte order is big-endian or little-endian?

19.26 How can I access an interrupt vector located at the machine's location 0? If I set a pointer to , the compiler might translate it to some nonzero internal null pointer value.

19.27 How can I invoke another program (a standalone executable, or an operating system command) from within a C program?

19.28 How can I call when parameters (filenames, etc.) of the executed command aren't known until run time?

19.29 How do I get an accurate error status return from on MS-DOS?

19.30 How can I invoke another program or command and trap its output?

19.31 How can my program discover the complete pathname to the executable from which it was invoked?

19.32 How can I automatically locate a program's configuration files in the same directory as the executable?

19.33 How can a process change an environment variable in its caller?

19.34 How can I open files mentioned on the command line, and parse option flags?

19.35 Is truly equivalent to returning the same from ?

19.36 How can I read in an object file and jump to locations in it?

19.37 How can I implement a delay, or time a user's response, with sub-second resolution?

19.38 How can I trap or ignore keyboard interrupts like control-C?

19.39 How can I handle floating-point exceptions gracefully?

19.39b How can I ensure that integer arithmetic doesn't overflow?

19.40 How do I... Use sockets? Do networking? Write client/server applications?

19.40a Can I combine .OBJ and .LIB files from Microsoft C and Turbo C?

19.40b How do I... Use BIOS calls? Write ISR's? Create TSR's?

19.40c I'm trying to compile this program, but the compiler is complaining that ``'' is undefined, and the linker is complaining that is undefined.

19.40d What are ``near'' and ``far'' pointers?

19.41 But I can't use all these nonstandard, system-dependent functions, because my program has to be ANSI compatible!

19.42 Why isn't any of this standardized in C? Any real program has to do some of these things.


20. Miscellaneous

20.1 How can I return multiple values from a function?

20.2 What's a good data structure to use for storing lines of text? I started to use fixed-size arrays of arrays of , but they're just too restrictive.

20.3 How can I open files mentioned on the command line, and parse option flags?

20.4 What's the right way to use ?

20.5 How can I write data files which can be read on other machines with different word size, byte order, or floating point formats?

20.6 If I have a variable pointing to the name of a function, how can I call that function? Code like

extern int func(int, int); char *funcname = "func"; int r = (*funcname)(1, 2); or r = (*(int (*)(int, int))funcname)(1, 2); doesn't seem to work.

20.6b How can I ensure that integer arithmetic doesn't overflow?

20.7 How can I manipulate individual bits?

20.8 How can I implement sets or arrays of bits?

20.9 How can I determine whether a machine's byte order is big-endian or little-endian?

20.9b How do I swap bytes?

20.10 How can I convert integers to binary or hexadecimal?

20.11 Can I use base-2 constants (something like )?
Is there a format for binary?

20.12 What is the most efficient way to count the number of bits which are set in an integer?

20.13 What's the best way of making my program efficient?

20.14 Are pointers really faster than arrays? How much do function calls slow things down? Is faster than ?

20.15 I've been replacing multiplications and divisions with shift operators, because shifting is more efficient.

20.15b People claim that optimizing compilers are good and that we no longer have to write things in assembler for speed, but my compiler can't even replace with a shift.

20.15c How can I swap two values without using a temporary?

20.16 Which is more efficient, a statement or an / chain?

20.17 Is there a way to on strings?

20.18 Is there a way to have non-constant labels (i.e. ranges or arbitrary expressions)?

20.19 Are the outer parentheses in statements really optional?

20.20 Why don't C comments nest? How am I supposed to comment out code containing comments? Are comments legal inside quoted strings?

20.20b Why isn't there a numbered, multi-level statement to break out of several loops at once? What am I supposed to use instead, a ?

20.21 There seem to be a few missing operators, like , , and .

20.21a Does C have circular shift operators?

20.21b Is C a great language, or what? Where else could you write something like ?

20.22 If the assignment operator were , wouldn't it then be harder to accidentally write things like ?

20.23 Does C have an equivalent to Pascal's statement?

20.24 Why doesn't C have nested functions?

20.24b What is and when would I use it?

20.25 How can I call FORTRAN (C++, BASIC, Pascal, Ada, LISP) functions from C? (And vice versa?)

20.26 Does anyone know of a program for converting Pascal or FORTRAN (or LISP, Ada, awk, ``Old'' C, ...) to C?

20.27 Is C++ a superset of C? What are the differences between C and C++? Can I use a C++ compiler to compile C code?

20.28 I need a sort of an ``approximate'' strcmp routine, for comparing two strings for close, but not necessarily exact, equality.

20.29 What is hashing?

20.30 How can I generate random numbers with a normal or Gaussian distribution?

20.31 How can I find the day of the week given the date?

20.32 Is an accurate test for leap years? (Was 2000 a leap year?)

20.33 Why can in the structure range from 0 to 61, suggesting that there can be 62 seconds in a minute?

20.34 Here's a good puzzle: how do you write a program which produces its own source code as output?

20.35 What is ``Duff's Device''?

20.36 When will the next International Obfuscated C Code Contest (IOCCC) be held? How do I submit contest entries? Who won this year's IOCCC? How can I get a copy of the current and previous winning entries?

20.37 What was the keyword mentioned in K&R1?

20.38 Where does the name ``C'' come from, anyway?

20.39 How do you pronounce ``''? What's that funny name for the ``'' character?

20.39b What do ``lvalue'' and ``rvalue'' mean?

20.40 Where can I get extra copies of this list?


Glossary


Bibliography


Acknowledgements


top

How to avoid memory Corruption

Written by Embarcadero USA on Posted in PROGRAMMING

Technical Notes Database TN3049C.txt How to avoid memory Corruption Category :OTHER Platform :All Product :BC All Description: Memory Corruption POINTERS: A pointer is a memory location that holds a memory address as its contents. When you declare a pointer (e.g. int *foo) the compiler will allocate the necessary space to hold the appropriate memory address. If the pointer is declared globally the value of its address will be 0000 in the case of a near pointer and 0000:0000 in the case of a far pointer. If the pointer is declared inside a function definition as an auto variable (default), then it is created on the stack and will have a default address of what ever value happened to be at that location on the stack when it is created. In either case these default memory addresses are invalid. This is referred to as an uninitialized pointer and should never be dereferenced. To initialize a pointer you must either dynamically allocate memory using malloc, farmalloc, calloc, farcalloc, realloc, farrealloc, allocmem or new (C++ only) or you can associate the pointer with a variable who's memory is allocated by the compiler at compile time (e.g. int foo[100]). Once the pointer has been initialized it is then safe to dereference the pointer using the * operator. int *p; OK Uninitialized pointer *p = 4; WRONG This puts a value of 4 at whatever address happened to be stored where *p was created. int i; OK Statically declared varible. Static meaning the memory is allocated by the compiler at compile time. p = &i; OK Associating p with a statically declared varible. p = (int *) malloc(2); Associating p with dynamically allocated OK memory. The parameter could also have been sizeof(int). Modifying the variable p (e.g. p = 0;) will make the memory address that p holds equal to 0. When modifying dereferenced p, denoted by *p, the value stored at the memory address p holds as its value is modified. *p = 4; OK p still holds the address that malloc returned above, but that address in memory now holds a value of 4. p = 4; OK* p now points to offset 4 from DS. It is important to note that this type of assignment should only be made if the address (4 in this case) is valid. Otherwise memory corruption will occur. Also note that if a far memory model (see Memory Models) is used the segment will not be DS but what ever its initial value was it will remain unchanged. There are 3 types of pointers. They are near, far, and huge. Near pointers have a size of 2 bytes. They only store the offset of the address the pointer is referencing. An address consisting of only an offset has a range of 0 - 64K bytes starting from the beginning of DGROUP. A near pointer can be incremented and decremented using arithmetic operators (+, -, ++, and --) through the entire address range. Any attempt to increment a near pointer that has a value of 64K (0xffff) will result in a value of 0. This is referred to as wrapping the pointer. A corresponding result can be expected when attempting to decrement a pointer that contains an address of 0, except the result will be 64K instead of 0. In addition to being incremented and decremented, near pointers can be compared to one another using relational operators ( <, >, ==, >= and <= ). Far pointers have a size of 4 bytes. They store both the segment and the offset of the address the pointer is referencing. A far pointer has an address range of 0 - 1M bytes. It is important to understand that an addressing range of 1M does not remove the 640K barrier from the program. It means that the pointer can address the upper memory area (641 - 1M) which typically contains video memory, ROM and anything else that may be loaded high. A far pointer can be incremented and decremented using arithmetic operators. When a far pointer is incremented or decremented ONLY the offset of the pointer is actually incremented or decremented. The segment is never incremented by the arithmetic operators. This means that although a far pointer can address up to 1Mb of memory, it can only be incremented through 64Kb and the offset will start at zero again without changing the value of the segment. This is referred to as "wrapping" the pointer (e.g. 0F3E:FFFF + 1 = 0F3E:0000). When a far pointer is decremented from zero it will wrap the other way and become 64K. Far pointers are not unique. It is possible to have two far memory addresses that have different segments values and different offset values that address the same memory location e.g. 0777:2222 has an absolute address of 07770 + 2222 = 09992 and 0999:0002 has an absolute address of 09990 + 0002 = 09992. When relational operators are used on far pointers only the offsets are compared. For example: if we let a = 0777:2222 and let b = 0999:0002 then a == b would return false because this is equivalent to 2222 == 0002 which is in fact false. In other words relational operators will only work on far pointers if the segment values of the pointers being compared are the same. Huge pointers have a size of 4 bytes. They store both the segment and the offset of the address the pointer is referencing. A huge pointer has an address range of 0 - 1M bytes. A huge pointer can be incremented and decremented using arithmetic operators. The only difference between a far pointer and a huge pointer is that a huge pointer is normalized by the compiler. A normalized pointer is one that has as much of the address as possible in the segment, meaning that the offset is never larger than 15. A huge pointer is normalized only when pointer arithmetic is performed on it. It is not normalized when an assignment is made. You can cause it to be normalized without changing the value by incrementing and then decrementing it. The offset must be less than 16 because the segment can represent any value greater than or equal to 16 (e.g. Absolute address 0x17 in a normalized form would be 0001:0001. While a far pointer could address the absolute address 0x17 with 0000:0017, this is not a valid huge (normalized) pointer because the offset is greater than 0000F.). Huge pointers can also be incremented and decremented using arithmetic operators, but since they are normalized they will not wrap like far pointers. Huge pointers can be reliably used with relational operators because they are normalized. This works because normalization of huge pointers insures that every huge pointer is unique. It is important to understand that huge pointers are never the default pointer, even in the huge memory model. MEMORY MODELS: The important difference between the memory models are the size of the data and code pointers, number of data and code segments and the number and type of heaps available. For our purposes we will refer to the tiny, small and medium memory models as near memory models and the compact, large and huge as far memory models. We use this notation because the near memory models have both a near and far heap while the far memory models have only a far heap. The near memory models do not have a separate stack segment like the far memory models do. This is because the data segment, the near heap and the stack are all part of DGROUP meaning that the total size of these things must be less than or equal to 64K bytes. The tiny model is an exception to this in that it also includes the code segment and psp (256 bytes) in DGROUP also. TINY SML MED CMP LRG HUGE Near Heap : Yes Yes Yes No No No Far Heap : Yes Yes Yes Yes Yes Yes Code pointers : near near far near far far Data pointers : near near near far far far Separate stack segment: No No No Yes Yes Yes Multiple code segments: No No Yes No Yes Yes Multiple data segments: No No No No No Yes The near and far heap fields above indicate the whether or not those heaps exist in the specified memory model. If a memory model is used that doesn't contain a near heap and one or more of the near heap functions i.e. malloc, free, heapwalk etc. are used they are mapped by the compiler into a special far version of the call that will allocate the memory off the correct heap (far). All of the parameters of these special near memory allocation functions are the same, but the pointer returned by this special version of the near memory allocation function will be a far pointer rather than a near pointer. The code and data pointer fields show the default pointer size for each memory model. It is important to note that none of the memory models use huge pointers by default. These defaults can all be overridden using the modifiers near, far or huge (e.g. int far *foo; or void near goo();). The separate stack segment field indicates whether the stack is part of DGROUP or in its own segment. Multiple code and data segments indicate if the specified memory model can have more than one of each type. If more than one of either type is allowed the segments are divided based on their corresponding source files e.g. a 3 source file program in the huge memory model would have 3 code segments and 3 data segments where the code and global data declared in each source file would go into the corresponding segment. HEAP: The global variable _heaplen only applies to the near heap. It is used to specify the size of the heap. If no value is specified for _heaplen then DGROUP will default to 64K bytes. If a value is specified then the size of DGROUP will be computed by summing the size of everything in DGROUP and then adding the size of _heaplen and _stklen. The global variable _stklen is used to specify how much memory to set aside for the stack. The near heap, when present, begins just after the global data and grows up toward the stack (higher memory) and the stack is situated at the end of DGROUP and grows down toward the heap (lower memory). The empty space separating the near heap and the stack can be used by either the heap or the stack regardless of whether it was reserved using _heaplen or _stklen variables. It is possible to dynamically allocate memory that is actually being used by the stack without generating a warning or an error. This is a common cause of memory corruption and can be avoided by using coreleft to keep track of the available memory to insure it is available prior to allocating it. The far heap exists just above the stack in memory. The far heap's initial size is zero. When the program processes a request for memory from the far heap it requests DOS to reallocate the current program size (minimum of 16 byte chunks) to include the requested size. DOS maintains its own heap very similar to the heap used by a program. Each block of memory that DOS allocates has a header called a memory control block (MCB) which is used to manage the heap used by DOS. When there is 1K bytes of free memory at the top of the far heap the program again calls DOS to reallocate the program space giving the memory back to DOS. All pointers used to reference the far heap should be either far or huge since the far heap is in a separate segment. It is important to note that if another process requests memory from DOS and the memory is available then that other program will get the next free block DOS owns which is the one immediately following the far heap in memory. This means that the next time your program attempts to reallocate the current program size the DOS allocate function will fail because your program has now been blocked in by a DOS memory control block (MCB) other than your program MCB. This is also the case if allocmem is called from within your program. STACK: Stack checking is an option that can be turned on or off that will check to see if the stack has overflowed. When this option is turned on the compiler will generate code that will check, upon entering a new function, to insure there is adequate room on the stack to make the call. If there isn't room the appropriate error message will be generated and the program will exit. The checking is done in the near memory models by comparing __brklvl that marks the end of the near heap and SP which marks the actual top of the stack. In the far memory models this checking is done by comparing SP which marks the actual top of the stack and _stklen which is the size of the stack segment. Stack checking is not fool proof. The Run Time Library (RTL) of functions found in the Library Reference Manual were not compiled with stack checking turned on. This means there is a possibility of overflowing the stack when making a call to an RTL function even though stack checking is turned on. Functions that use a stack other than the program stack should not use the stack checking option (e.g asynchronous interrupt service routines). When floating point is turned on in any memory model the floating point emulator information is located in the first 416 bytes of the physical stack (SS:0000 - SS::415). This information must be transferred if you are trying to switch stacks. Receiving false floating point error messages is a good indication that something may be corrupting this portion of the stack. The size of the stack is determined by the startup code at run time. If a link map is generated you will see a size specified for the stack that may be different than the size you specified. This value you see in the link map is a value that DOS is told, but the actual size requirement is met at runtime. In the near memory models the stack exists within the 64K byte limit defined by DGROUP which also contains global data and the near heap. In the tiny memory model it also contains the code segment. In the near memory when the stack overflows the first thing corrupted is the near heap followed by the global data. In the far memory models the stack exists immediately following the data segment and is just before the far heap. In the far memory models the first thing that is corrupted when the stack overflows is the floating point emulator followed by the far heap. In order to avoid stack overflow it is important to understand what makes up the stack. In the far memory model only, the emulator occupies the 416 bytes from SS:0000 to SS:0415 located at the top of the logical stack. As each function is entered space is allocated for all its parameters. They are created on the stack from right to left followed by the return address. Space is then allocated for all auto (default for local variables) variables in the order of declaration. All this space remains allocated until the function returns to the calling function. In other words if you then called another function, then the space allocated for the first function would remain allocated until the first function regained control and then returned control to it calling function. In the case of C++ programs, all class copies used by the compiler are implicitly created on the stack unless a copy constructor is provided that uses the alternative of dynamic memory allocation. COMMON PROBLEMS LEADING TO MEMORY CORRUPTION: Using an uninitialized pointer is probably the most common cause of memory corruption. It is possible to use an uninitialized pointer and have a program work. It just depends on what the default address is when the pointer is created and if anything else is attempting to use that address. Failure to include ALLOC.H is a common mistake. When ALLOC.H is left out the type checking is not performed. Since there is no prototype the memory allocation functions are all thought by the compiler to be returning integer types. A program will usually continue to work without ALLOC.H in the near memory models, since an integer is the same size as the near pointers used in these memory models. However in the far memory models the segment half of the pointer is lost when the memory allocation function attempts to return a far pointer. These programs may or may not work. You should always include ALLOC.H. Failure to check the return value from a memory allocation call can result in a NULL pointer. Technically a NULL pointer is defined as an invalid pointer. In more practical use, however, a NULL pointer is interpreted as meaning a pointer that holds 0 as its address (e.g. p = 0;). NULL for our purposes will mean a pointer that holds an address of 0. A memory allocation function can fail and return NULL if there is no memory left, the program was unable to resize its MCB or if there is some sort of heap corruption whether it be in the DOS heap or your program heap. Your code should always check to insure the pointer returned by a memory allocation function is not NULL. Stack overflow is a common problem. When making a function call the stack can overflow and corrupt some other variables and return without the user being the wiser. A later attempt to use the corrupted variable can result in incorrect program results or hanging the system. Indexing out of bounds occurs with both statically declared arrays and dynamically declared arrays. An array declared as char foo[100] has a valid index range of 0 - 99. Making an assignment to foo[100] is memory corruption since foo[100] does not belong to the array foo. A non-huge array will wrap if an a value larger than unsigned (0xffff) is used to index it. The largest dynamically allocated array that can be addressed using a far pointer is 65531 bytes because the offset returned by farmalloc will always have an offset of 0004. This offset is guaranteed because the far heap is paragraph aligned. The missing 4 bytes are used by the program heap manager as a block header to manage the heap. Of course a far pointer has the potential to rival the power available with the huge pointers if the user does the necessary normalizing of the pointer. In a far memory model, a call to a near memory function will be mapped into the corresponding special function call described above in the heap section. In the near memory models all pointers declared are near by default and should not be used with any of the far memory allocation functions i.e. farmalloc and farcalloc. The compiler will generate a warning about a suspicious pointer conversion but it won't prevent it from happening. The first time such a pointer is used it will address an offset of 0004 in the DGROUP. Also be aware of the memory model that the program is compiled in. If it is one of the far memory models then all calls to the near memory allocation functions will be mapped into the corresponding far functions behind the scenes by the compiler. In some cases this also changes the parameter and return types. It is strongly suggested that if you are using a far memory model you use only the far memory allocation functions to avoid confusion at a later date and make debugging easier. The duration of a variable is very important. A global pointer should never reference a local auto variable, because when that local variable goes out of scope its memory is released to be reused by the stack for something else. If the global pointer is later used it may be erroneously referencing something else. Receiving the message "Null pointer assignment" after your program has completed its run is usually caused by the use of an uninitialized pointer. You can track the cause of this message down by placing the two watches ( (char *)4,s and *(char *) 0,4m ) on your program. The first 47 bytes of the data segment are not valid addresses for any variables in your program. When your program exits these 47 bytes are checked to see if they have been modified. If they have the warning message is printed on your screen. These two watches will allow you to monitor the beginning of the data segment to identify the offending line of code. The memory allocation functions used to free dynamically allocated memory (free, farfree, delete) should only be used on pointers that hold an address returned by a dynamic memory allocation function i.e. farmalloc, malloc, new etc.. Any attempt to free an array declared as int foo[100] will result in undefined results possibly corrupting memory. The memory freeing functions should never be called twice with the same address as a parameter unless that same address has been reallocated since the last memory free function call. The results are undefined and can produce memory corruption. One very common problem is character arrays that are not NULL terminated. Every character array must be terminated by a NULL or 0 i.e. char foo[100]; foo[0] = 0; This is a NULL terminated "empty" string foo[10] = '\0'; This is a NULL terminated string with 10 undefined characters preceding the NULL. Remember indexing starts at 0 not 1. foo[0] = '0' Incorrect this is not a NULL terminated string. All of the functions that are listed in string.h found in the include directory rely on this NULL termination. The NULL is what they use to tell them to they have reached the end of the string and should stop processing the string. If the NULL is missing then these functions will continue on processing possibly corrupting memory as they go. For most of the string family of functions list in string.h you will see a corresponding n family of functions i.e. strcpy and strncpy, stricmp and strnicmp, strcat and strncat etc.. The corresponding n functions perform the same tasks as their corresponding counter parts with the exception that they take an extra parameter n which specifies how many characters in the string to operate on. These n functions will be finished when they have processed the string up to the NULL character or until they have processed n characters in the string. It is strongly recommended that these n family of functions be used rather than their counterparts because if they do receive a string that is not NULL terminated they will stop after they have processed n characters rather than continuing on and corrupting memory. You will also see an _f family of functions in string.h that have corresponding standard and n family of functions i.e. strcat and _fstrcat; strchr and _fstrchr; strncmp and _fstrncmp etc.. The _f family of functions is not limited to the string family of functions and will be addressed later. In general most functions that work with pointers have a corresponding _f family functions. The _f family of functions were designed for use exclusively in the small and medium memory models because they are the only memory models that have both a near and a far heap. The _f family of functions are designed for use with far pointers in the small and medium memory models. They are not necessary in the far memory models because those RTL functions have already been compiled using the default far pointers as parameter and return types. Near pointers present no special problems in the far memory models because they can be implicitly converted by the compiler. The C++ language presents some special problems due to constructors and destructors which are called by the compiler automatically. The first rule is that for every constructor call there must be a corresponding destructor call. If no dynamic memory allocation and deallocation is taking place in these constructors and destructors one may not even notice if the destructor gets called twice, but if it is the heap will most likely become corrupted. One can check for violations of this property by placing simple print statements or breakpoints (if using a debugger) in each of the constructors and destructors and check for compliance. If dynamic memory allocation is used in a constructor in C++ then a copy constructor is almost always required. A copy constructor is a constructor that will dynamically allocate the needed memory and then copy what is stored in the corresponding memory in the class instance being copied. The compiler will often times need to generate temporaries of the class instances e.g. when an instance is being passed as a parameter. If a copy constructor is not defined it will use the default memberwise copy resulting in two different pointers in two different class instances pointing to the same dynamically allocated memory. This means that when the first instance is destructed the memory addressed by its pointer is freed leaving the remaining instance of the class with an invalid pointer that if used will cause memory corruption. If a copy constructor is defined the compiler will use it versus the default copy constructor. DEBUGGING TIPS AND TECHNIQUES: Once you are sure that the problem is not one of the common mistakes listed you roll up your sleeves and prepare for a real debugging session. The real trick to debugging is to understand how memory works and how a program is structured in that memory. If you understand these things then you can use things like different size pointers and different segment organization to debug your program. Switching memory models makes all these things happen. The hard part is knowing which one to switch to and what to look for when you get there. In some cases you may not be able switch memory models due to program constraints and may be forced to use other techniques. When none of the simpler tricks such as changing memory models works, then the divide and conquer technique should be used. The divide and conquer method is the most reliable method, but it is often the most difficult to implement. A good technique to employ in your programming is to initialize all pointers to NULL when they are declared and and again after they have been freed. This way all invalid pointers will contain the same address and can be tested prior to use and prior to being freed. All compiler warnings should be turned on. It is important to note that the compiler isn't shipped with all the warnings turned on. Inside the IDE you have to turn each warning on explicitly and on the command line you should give the -w+ option. You can find more information about how to turn these on in the users guide. In a near memory model the stack and the near heap grow towards each other in memory. It is possible for either one to overstep its bounds and corrupt the other. This condition is easy to test for by moving to a far memory model and then increase the stack size to 64K. If the program then behaves differently this is a strong indication that one or the other of these conditions existed. If this is the case, there are two possible solutions. The first is to use the far memory allocation functions and the second is to stay in the far memory model and adjust the stack size as necessary. In the far memory models the stack exists directly below the far heap in memory. As the stack grows the stack pointer SP approaches zero. When the stack overflows SP jumps from 0 to 0xffffh. If the stack has been declared to be 64K then the beginning of the logical stack will be corrupted else the far heap at a point exactly 64k higher in memory from SS will be corrupted. Note if you are using floating point the emulator located on the top of the logical stack will become corrupted before SP even wraps. This could result in a program running OK, but giving incorrect results from computations or aborting the program. The stack size can be increased to 64K by the line "extern unsigned _stklen = 0xffffu;" at file scope (outside any function definition) inside any source file being linked into your program. A common mistake in writing an overloaded operator is to allocate a new instance of a class, calculate the new value of this instance, and return the pointer to this new instance. This will work, but the compiler has no way of knowing that it should free up the new data after it has finished with it. A program may work "perfectly" on small amounts of data, but crash after it has exhausted most of available memory. This is called a "memory leak". Overloading NEW and DELETE to keep a log of used/freed memory will assist in tracking these leaks. When debugging a live program, it is easy to display and verify an integer, string or other simple data structure. Verification of more complex structures may involve several layers of pointer indirection. It may be tedious to examine all elements in a linked list for example. If you write functions to check your structures/classes, these can be called within your program at debug time. For instances of classes, these should be virtual member functions, so that the correct routine is called for instances of derived classes accessed through base class pointers. Call these functions at the start and end of all other member functions to flag corrupted data and assist in isolating problems. The divide and conquer method is implemented by manipulating the different components composing the program. These components will most likely be single functions or groups of functions that lend themselves to being individually tested by a driver program. A driver program is a small program used to test a particular module or group of modules. It should set up the environment for and pass the parameters required by the function being tested. Sometimes it may be more desirable to test an entire program without a particular function. This can be done by using a stub. A stub is a testing function designed to take the same parameters and return the same type as the function it is replacing. Once the offending function has been located the offending line of code must be located by commenting out and changing various lines within the function. When You have identified what you suspect as being the offending line of code you need to confirm this. This is done by writing a separated test program to test the line of code all by itself. If it still doesn't work correctly then you have found the problem. If it works in the example program then you have most likely found a side effect caused by something else that must be identified. For instance something else may modify the value of a pointer that , when used by the suspect code, causes the machine to hang. Enough information should be obtained from the code producing the side effect to give you a new place to look. In our example we would watch the address of the pointer that got corrupted by using Turbo Debugger and setting a hardware breakpoint on the address of the pointer that would stop program execution whenever the pointer value is modified. It is rare that an identified problem needs more than 20 lines of code to reproduce. Once you feel that you have isolated it you should ask yourself is every piece of code in your example necessary to reproduce the problem. For instance if the problem requires a structure to manifest itself then what the structure contains is probably not important. The divide portion of the algorithm is usually the most difficult and the most time consuming. Now the you have located the problem you can usually determine what the cause was. If you know what the cause of the problem was you should be able to summarize the problem in a few sentences. If you cannot do this you probably don't have a complete grasp of the problem. Borland technical support will be able to provide you with the best support when you have the problem isolated and have reproduced it in an small example. Whether you are just letting us know the problem is there or you're not sure what is causing the problem. A function familiar to C programmers is the assert() macro. This function is well suited for C++ programming. Assert() takes an expression as a parameter, and if the expression is false, usually halts the program and prints a message giving the line number and file where the problem occurred. At any point where an important assumption is made about the correctness of calculated data, insert an assert() call, which will display a message if the assumptions is invalid. For example, the default for a switch statement is an ideal place to insert an assert() call. Insure that you include ASSERT.H. Defining the symbol "NDEBUG" will cause the compiler to ignore (i.e. not generate code for) all assert() calls. This way the source code will not have to be modified to remove the excess debugging code. Reference: 7/2/98 10:43:13 AM

Article originally contributed by

Tags: C++BuilderPlatformsProgrammingPerformanceDOSWin16



One thought on “Null Pointer Assignment Turbo Cars

Leave a Reply

Your email address will not be published. Required fields are marked *