* There are a number of common programming pitfalls in C that even trap experienced programmers:
1: Confusing "=" (assignment operator) with "==" (equality operator). For example:
if ( x = 1 ) {
}
-- is bogus, and so is: for ( x == 1; ...
2: Confusing precedence of operations in expressions. When in doubt, use parentheses to enforce precedence.
3: Confusing structure-member operators. If "struct_val" is a structure and "struct_ptr" is a pointer to a structure, then:
struct_val->myname -- is wrong and so is: struct_ptr.myname
4: Using incorrect formatting codes for "printf()" and "scanf()". Using a "%f" to print an "int", for example, can lead to bizarre output.
5: Remember that the actual base index of an array is 0, and the final index is 1 less than the declared size. For example:
int data[20]; ... for ( x = 1; x <= 20; ++x ) { printf( "%d\n", data[x] ); }
-- will give invalid results when "x" is 20. Since C does not do bounds checking, this one might be hard to catch.
6: Muddling syntax for multidimensional arrays. If: data[10][10]
-- is a two-dimensional array, then: data[2][7]
-- will select an element in that array. However: data[ 2, 7 ]
-- will give invalid results but not be flagged as an error by C.
7: Confusing strings and character constants. The following is a string: "Y"
-- as opposed to the character constant: 'Y'
This can cause troubles in comparisons of strings against character constants. 8: Forgetting that strings end in a null character ('\0'). This means that a string will always be one character bigger than the text it stores. It can also cause trouble if a string is being created on a character-by-character basis, and the program doesn't tack the null character onto the end of it.
9: Failing to allocate enough memory for a string -- or, if pointers are declared, to allocate any memory for it at all.
10: Declaring a string with a fixed size and then assigning it to a string literal: char a[256] = "This doesn't work!";
11: Failing to check return values from library functions. Most library functions return an error code; while it may not be desireable to check every invocation of "printf()", be careful not to ignore error codes in critical operations.
Of course, forgetting to store the value returned by a function when that's the only way to get the value out of it is a bonehead move, but people do things like that every now and then.
12: Having duplicate library-function names. The compiler will not always catch such bugs.
13: Forgetting to specify header files for library functions.
14: Specifying variables as parameters to functions when pointers are supposed to be specified, and the reverse. If the function returns a value through a
parameter, that means it must be specified as a pointer: myfunc( &myvar );
The following will not do the job: myfunc( myvar );
Remember that a function may require a pointer as a parameter even if it doesn't return a value, though as a rule this is not a good programming practice.
15: Getting mixed up when using nested "if" and "else" statements. The best way to avoid problems with this is to always use brackets. Avoiding complicated "if" constructs is also a good idea; use "switch" if there's any choice in the matter. Using "switch" is also useful even for simple "if" statements, since it makes it easier to expand the construct if that is necessary.
16: Forgetting semicolons -- though the compiler usually catches this -- or adding one where it isn't supposed to be -- which it usually doesn't. For example:
for( x = 1; x < 10; ++x ); {
printf( "%d\n", x ) }
-- never prints anything.
17: Forgetting "break" statements in "switch" constructs. As commented earlier, doing so will simply cause execution to flow from one clause of the "switch" to the next.
18: Careless mixing and misuse of signed and unsigned values, or of different data types. This can lead to some insanely subtle bugs. One particular problem to watch out for is declaring single character variables as "unsigned char". Many I/O functions will expect values of "unsigned int" and fail to properly flag EOF. It is recommended to cast function arguments to the proper type even if it appears that type conversion will take care of it on its own.
19: Confusion of variable names. It is recommended that such identifiers be unique in the first 6 characters to ensure portability of code.
20: In general, excessively tricky and clever code. Programs are nasty beasts and even if it works, it will have to be modified and even ported to different languages. Maintain a clean structure and do the simple straightforward thing, unless it imposes an unacceptable penalty.
STDIO.H
stdio.h, which stands for "standard input/output header", is the header in the C standard library that contains macro definitions, constants, and declarations of functions and types used for various standard input and output operations. Functions declared in stdio.h are extremely popular, since as a part of the C standard library, they are guaranteed to work on any platform that supports C Functions declared in stdio.h can generally be divided into two categories: the functions for file manipulation and the functions for input-output manipulation.
Name Notes
File manipulation functions
fclose closes a file associated with the FILE * value passed to it
fopen, freopen opens a file for certain types of reading or writing
remove removes a file (deletes it)
rename renames a file
rewind acts as if fseek(stream, 0L, SEEK_SET) was called for the stream
passed, and then its error indicator cleared
Input-output manipulation functions
clearerr clears end-of-file and error indicators for a given stream
feof checks whether an stream end-of-file indicator has been set for a given
ferror checks whether an error indicator has been set for a given stream
fflush forces any pending buffered output to be written to the file
associated with a given stream
fgetpos stores the file position indicator of the stream associated by its
first argument (a FILE *) to its second argument (a fpos_t *)
fgetc returns one character from a file
fgets gets a string from the file (ending at newline or end-of-file)
fputc writes one character to a file
fputs writes a string to a file
ftell returns a file-position indicator which can then be passed to fseek
fseek seeks through a file
fread reads data from a file
fwrite writes data to a file
getc
reads and returns a character from a given stream and advances the file position indicator; it is allowed to be a macro with the same effects as fgetc, except that it may evaluate the stream more than once
getchar has the same effects as getc(stdin)
gets reads characters from stdin until a newline is encountered and stores them in its only argument
printf, vprintf used to print to the standard output stream
fprintf, vfprintf used to print to a file
sprintf, snprintf, vsprintf, vsnprintf
used to print to a char array (C string)
perror writes an error message to stderr
putc writes and returns a character to a stream and advances the file position indicator for it; equivalent to fputc, except that a macro version may evaluate the stream more than once
putchar,
fputchar has the same effects as putc(stdout)
fscanf, vfscanf used to input from a file
sscanf,
vsscanf used to input from a char array (e.g., a C string)
setbuf, setvbuf sets the buffering mode for a given stream
tmpnam creates a temporary filename
ungetc pushes a character back onto a stream
puts outputs a character string to stdout
conio.h
conio.h is a C header file used in old MS-DOS compilers to create text user interfaces. It is not described in The C Programming Language book , and it is not part of the C standard library, ISO C nor is it required by POSIX.
Member functions
int kbhit(void) Determines if a keyboard key was pressed.
int getch(void) Reads a character directly from the console without buffer, and without echo.
int getche(void) Reads a character directly from the console without buffer, but with echo.
char *cgets(char *buffer) Reads a string directly from the console.
int cscanf(char *format,
arg0,... argn) Reads formated values directly from the console.
int putch(int c) Writes a character directly to the console.
int cputs(const char *string) Writes a string directly to the console.
int cprintf(const char *format, arg0,... argn)
Formats values and writes them directly to the console.
string.h
string.h is the header in the C standard library for the C programming language which contains macro definitions, constants, and declarations of functions and types used not only for string handling but also various memory handling functions; the name is thus something of a misnomer.
Functions declared in string.h are extremely popular, since as a part of the C standard library, they are guaranteed to work on any platform which supports C. However, some security issues exist with these functions, such as buffer
overflows, leading programmers to prefer safer, possibly less portable variants.
Functions
Name Notes
void *memcpy(void *dest, const void *src, size_t n);
copies n bytes between two memory areas, which must not overlap
void *memmove(void *dest, const void *src, size_t n);
copies n bytes between two memory areas; unlike with memcpy the areas may overlap
void *memchr(const void *s, char c, size_t n);
returns a pointer to the first occurrence of c in the first n bytes of s, or NULL if not found
int memcmp(const void *s1, const void *s2, size_t n);
compares the first n characters of two memory areas
void *memset(void *, int,
size_t); overwrites a memory area with a byte pattern
char *strcat(char *dest, const
char *src); appends the string src to dest
char *strncat(char *, const char *, size_t);
appends at most n characters of the string src to dest
char *strchr(const char *, int); locates a character in a string, searching from the beginning
char *strrchr(const char *, int); locates a character in a string, searching from the end
int strcmp(const char *, const
char *); compares two strings lexicographically
int strncmp(const char *, const char *, size_t);
compares up to the first n bytes of two strings lexicographically
int strcoll(const char *, const char *);
compares two strings using the current locale's
collating order
char *strcpy(char *toHere,
char *strncpy(char *toHere, const char *fromHere, size_t);
copies up to n bytes of a string from one location to another
char *strerror(int); returns the string representation of an error number e.g. errno (not thread-safe)
size_t strlen(const char *); finds the length of a C string
size_t strspn(const char *s, const char *accept);
determines the length of the maximal initial substring of s consisting entirely of characters in accept
size_t strcspn(const char *s, const char *reject);
determines the length of the maximal initial
substring of s consisting entirely of characters not in reject
char *strpbrk(const char *s, const char *accept);
finds the first occurrence of any character in accept in s
char *strstr(const char *haystack, const char *needle);
finds the first occurrence of the string "needle" in the longer string "haystack".
char *strtok(char *, const char *);
parses a string into a sequence of tokens; non- thread safe in the spec, non-reentrant
size_t strxfrm(char *dest, const char *src, size_t n);
transforms src into a collating form, such that the numerical sort order of the transformed string is equivalent to the collating order of src.