Download presentation
Presentation is loading. Please wait.
1
Real C C Traps and Pitfalls Partially based on: C Traps & Pitfalls, A. Koenig Various resources from the WWW
2
Overview C traps and pitfalls And some programming tips A bit about OOP and OOD With some related Buzz-Words Introduction to project development lifecycle
3
Greedy lexer Take a look at the following function: double devide_by_pointer(double x, double *p) { double ret; ret = x/*p;/* p points at the divisor */ } double devide_by_pointer(double x, double *p) { double ret; ret = x/*p;/* p points at the divisor */ } greedy1.c
4
Greedy lexer The lexer is a part of the compiler that breaks the code text into tokens It greedy - bites off the biggest possible piece of text == is a single token Whereas = = are two tokens a---b is the same as a -- - b But not a - -- b == is a single token Whereas = = are two tokens a---b is the same as a -- - b But not a - -- b
5
Greedy lexer In the early days =+ was the what now is += Why did they change it ? a=-1; a=-1; This is actually: a = a – 1; This is actually: a = a – 1; But we meant: a = –1; But we meant: a = –1;
6
Integer constants C allows very convenient ways to set integer constants /* My error codes */ #define EVERYTHING_OK0000 #define NON_RECOVERABLE_ERROR9999 #define ILLEGAL_PARAMETER_A0001 … #define NOT_CONNECTED0010 … /* My error codes */ #define EVERYTHING_OK0000 #define NON_RECOVERABLE_ERROR9999 #define ILLEGAL_PARAMETER_A0001 … #define NOT_CONNECTED0010 … 0010 is octal => 8 decimal 0010 is octal => 8 decimal
7
Strings and Characters Single quotes ’a’ are very different from double quotes ”a” Writing: char c = ‘a’ is just the same as char c = 0141 or 97 Writing: char *hello = “hello” is a pointer to the initial character to an array Writing: char c = ‘a’ is just the same as char c = 0141 or 97 Writing: char *hello = “hello” is a pointer to the initial character to an array Nameless array: ‘h’,’e’,’l’,’l’,’o’
8
Strings and Characters Consider this case Whats the difference between: printf(‘\n’);and printf(“\n”); Whats the difference between: printf(‘\n’);and printf(“\n”);
9
Operator precedence Testing bits … #define ERROR_BIT 0x04 … { … if (flags & ERROR_BIT) { /* handle error */ } … #define ERROR_BIT 0x04 … { … if (flags & ERROR_BIT) { /* handle error */ }
10
Operator precedence Testing bits … #define ERROR_BIT 0x04 … { … if (flags & ERROR_BIT != 0) { /* handle error */ } … #define ERROR_BIT 0x04 … { … if (flags & ERROR_BIT != 0) { /* handle error */ }
11
Operator precedence Testing bits … #define ERROR_BIT 0x04 … { … if (flags & (ERROR_BIT != 0)) {BUG /* handle error */ } … #define ERROR_BIT 0x04 … { … if (flags & (ERROR_BIT != 0)) {BUG /* handle error */ } if ((flags & ERROR_BIT) != 0) {OK if ((flags & ERROR_BIT) != 0) {OK
12
Operator precedence 2 nd Suppose we have to integer variables hi and low Each are between [0..15] (4 bits) We want to build an 8 bit number out of both of them i = hi*16+lo; Works but uses multiplication i = hi << 4 + low; Bug: i = hi << (4 + low) Fix is either: i = (hi << 4) + low i = hi << 4 | low; i = hi*16+lo; Works but uses multiplication i = hi << 4 + low; Bug: i = hi << (4 + low) Fix is either: i = (hi << 4) + low i = hi << 4 | low;
13
Operator precedence 2 nd Use parenthesis i = (hi << 4) | low; if ((income > 4000) && (age > 18)) Etc. i = (hi << 4) | low; if ((income > 4000) && (age > 18)) Etc.
14
Watch Out for Semicolons int calc_max(int *x, int size) { for … { if (x[i] > big); big = x[i]; } int calc_max(int *x, int size) { for … { if (x[i] > big); big = x[i]; } The compiler will happily digest the semicolon to: if (x[i] > big) {} big = x[i]; if (x[i] > big) {} big = x[i];
15
Dangling else The meaning was two cases: x = 0 and x != 0 However else is associated with the closest unmatched if. if (x == 0) if (y == 0) error(); else { z = x + y; f(z); } if (x == 0) if (y == 0) error(); else { z = x + y; f(z); } if (x == 0) if (y == 0) error(); else { z = x + y; f(z); } if (x == 0) if (y == 0) error(); else { z = x + y; f(z); }
16
Dangling else Always use curly braces ‘{}’ with if-else statements if (x == 0) { if (y == 0) error(); } else { z = x + y; f(z); } if (x == 0) { if (y == 0) error(); } else { z = x + y; f(z); }
17
Pointers vs. Arrays C has only one-dimensional arrays Only two things can be done to an array Determine its size Obtain a pointer to element 0 Everything else is done using pointers ! Array declaration: int a[3]; struct { double v[3]; double length; } b[17]; int calendar[12][31]; sizeof(calendar) is 372 (12*31) int’s Array declaration: int a[3]; struct { double v[3]; double length; } b[17]; int calendar[12][31]; sizeof(calendar) is 372 (12*31) int’s
18
Pointers vs. Arrays Pointers may happen to point to an element of an array We can use that pointer to obtain a pointer to the next/previous element of that array Add/Subtract 1 for that pointer int a[10]; … int *p; p = a;/* take the pointer to a[0] */ p++;/* next element */ p--;/* previous element */ int a[10]; … int *p; p = a;/* take the pointer to a[0] */ p++;/* next element */ p--;/* previous element */
19
Pointers vs. Arrays Adding an integer to a pointer is different from adding that integer to the bit representation of that pointer int *p; p = p + 1; /* this advances p’s value (pointed- address) by sizeof(int) which is usually not 1 */ int *p; p = p + 1; /* this advances p’s value (pointed- address) by sizeof(int) which is usually not 1 */
20
Pointers vs. Arrays The name of the array is the same as a pointer to the array in every context but one int a[3]; int *p; p = a;/* p points to a[0] */ *a = 5;/* sets a[0] to 5 */ *(a+1) = 5;/* sets a[1] to 5 */ The only difference is in sizeof: sizeof(a)/* returns the size of the entire array not just a[0] */ int a[3]; int *p; p = a;/* p points to a[0] */ *a = 5;/* sets a[0] to 5 */ *(a+1) = 5;/* sets a[1] to 5 */ The only difference is in sizeof: sizeof(a)/* returns the size of the entire array not just a[0] */
21
Pointers vs. Arrays int a[3]; int i; a+i/* is the same as */ i+a/* is the same as */ &a[i] int a[3]; int i; a+i/* is the same as */ i+a/* is the same as */ &a[i]
22
Pointers are not Arrays Suppose we want to concatenate string s and string t into a single string char *r; strcpy(r, s); strcat(r, t); char *r; strcpy(r, s); strcat(r, t); char r[100]; strcpy(r, s); strcat(r, t); char r[100]; strcpy(r, s); strcat(r, t); Doesn’t work cause r doesn’t point anywhere. Lets make r an array – now it points to 100 chars This works as long as the strings pointed to by s and t aren’t too big
23
Pointers are not Arrays char r[strlen(s)+strlen(t)]; strcpy(r, s); strcat(r, t); char r[strlen(s)+strlen(t)]; strcpy(r, s); strcat(r, t); We would like to write something like: However C requires us to state the size of the array as constant. char *r; r = malloc(strlen(s)+strlen(t)); strcpy(r, s); strcat(r, t); char *r; r = malloc(strlen(s)+strlen(t)); strcpy(r, s); strcat(r, t); This fails for three reasons: 1.Malloc might fail to allocate the required memory 2.It is important to free the memory allocated 3.We did not allocate enough memory
24
Pointers are not Arrays The correct code will be: char *r; r = malloc(strlen(s)+strlen(t)+1); if (!r) { /* print some error and exit */ exit(1); } strcpy(r, s); strcat(r, t); /* later */ free(r); r = NULL;/* Try to reset free’d pointers to NULL */ char *r; r = malloc(strlen(s)+strlen(t)+1); if (!r) { /* print some error and exit */ exit(1); } strcpy(r, s); strcat(r, t); /* later */ free(r); r = NULL;/* Try to reset free’d pointers to NULL */
25
Copying pointers A common C pitfall is to confuse a pointer with the data to which it points char *p,*q; p = strdup(“xyz”); char *p,*q; p = strdup(“xyz”); ‘x’ ‘y’ ‘z’ ‘\0’ … q = p; q[1] = ‘A’;/* p would point to “xAz” too */ q = p; q[1] = ‘A’;/* p would point to “xAz” too */ ‘A’
26
Using CORE dumps On Unix (including Linux) a process is usually killed if it access memory incorrectly This usually happens due to pointers going mad and bad Before the process is killed important information on why it was killed is saved in a core file This information can be used to pinpoint what went wrong
27
Using CORE dumps #include int main() { int* i = NULL; *i = 5;/* This will cause a core dump in Unix/Linux */ return 0; } #include int main() { int* i = NULL; *i = 5;/* This will cause a core dump in Unix/Linux */ return 0; } Lets look at this faulty program (test.c) that tries to access a NULL pointer Running this program yields the expected error message: Segmentation fault (core dumped)
28
Using CORE dumps nova~> gdb myTest core GNU gdb Red Hat Linux (5.2-2) Copyright 2002 Free Software Foundation, Inc. Core was generated by `./myTest'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/i686/libc.so.6...done. Loaded symbols for /lib/i686/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x080483d0 in main () at test.c:6 6 *i = 5; (gdb) where #0 0x080483d0 in main () at test.c:6 #1 0x42017589 in __libc_start_main () from /lib/i686/libc.so.6 (gdb) nova~> gdb myTest core GNU gdb Red Hat Linux (5.2-2) Copyright 2002 Free Software Foundation, Inc. Core was generated by `./myTest'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/i686/libc.so.6...done. Loaded symbols for /lib/i686/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x080483d0 in main () at test.c:6 6 *i = 5; (gdb) where #0 0x080483d0 in main () at test.c:6 #1 0x42017589 in __libc_start_main () from /lib/i686/libc.so.6 (gdb) To use the core dump the program must be compiled with debug information. This is done by adding –g flag to the gcc compilation line For example: gcc –g test.c –o myTest (Make sure that your core file was generated while running the program compiled with debug information before continuing to the next step - you may need to run the program again after adding flag) Now run: gdb core and write ‘where’ at the prompt – you should get a stack trace and entry #0 is the source code line were the error had occurred. Here is the command line and output for our previous faulty program
29
Counting and Asymmetric Bounds int i,a[10]; for (i=0; i <= 9; i++) {... } While looping over arrays Always use asymmetric bounds: < instead of <= for (i=0; i < 10; i++) {... } int i,a[10]; for (i=0; i <= 9; i++) {... } While looping over arrays Always use asymmetric bounds: < instead of <= for (i=0; i < 10; i++) {... }
30
Macros Macros are not functions Even when written with all the parentheses #define MAX(a,b) (((a)>(b)) ? (a) : (b)) int a[4]; int biggest; biggest = x[0]; i = 1; while (i < 4) biggest = MAX(biggest, x[i++]); #define MAX(a,b) (((a)>(b)) ? (a) : (b)) int a[4]; int biggest; biggest = x[0]; i = 1; while (i < 4) biggest = MAX(biggest, x[i++]); This code would have worked fine if MAX was a function
31
Macros Let’s expand the macro: #define MAX(a,b) (((a)>(b)) ? (a) : (b)) int a[4]; int biggest; biggest = x[0]; i = 1; while (i < 4) biggest = (biggest > x[i++]) ? biggest : x[i++]; #define MAX(a,b) (((a)>(b)) ? (a) : (b)) int a[4]; int biggest; biggest = x[0]; i = 1; while (i < 4) biggest = (biggest > x[i++]) ? biggest : x[i++];
32
Macros Macros are not statements Lets try to write the assert macro assert(x > y); /* should print info only if x <= y */ #define assert(e) if (!(e)) assert_error(__FILE__,__LINE__) assert(x > y); /* should print info only if x <= y */ #define assert(e) if (!(e)) assert_error(__FILE__,__LINE__) if ((x > 0) && (y > 0)) assert(x > y); else assert(y > x); if ((x > 0) && (y > 0)) assert(x > y); else assert(y > x); This macro is not safe:
33
Macros assert(x > y); /* should print info only if x <= y */ #define assert(e) { if (!e) assert_error(__FILE__,__LINE__) } assert(x > y); /* should print info only if x <= y */ #define assert(e) { if (!e) assert_error(__FILE__,__LINE__) } if ((x > 0) && (y > 0)) { if (!(x > y)) assert_error(__FILE__,__LINE__) }; else { if (!(y > x)) assert_error(__FILE__,__LINE__) }; if ((x > 0) && (y > 0)) { if (!(x > y)) assert_error(__FILE__,__LINE__) }; else { if (!(y > x)) assert_error(__FILE__,__LINE__) }; This will solve the dangling else problem but will cause a problem with the semicolon: We can try and add braces: The correct solution is: #define assert(e) ((void)((e) || assert_error(__FILE__,__LINE__))) #define assert(e) ((void)((e) || assert_error(__FILE__,__LINE__)))
34
OOD and OOP
35
Some of C Strengths It is close to machine language Provides efficient code Highly portable Compile the code on different platforms Many newer languages are similar in syntax Both Linux and most Unix operation systems are written in C Even large parts of Windows are in C
36
Some of Its Weaknesses Surprising but Code efficiency is usually not so important More important are Shorter development times Higher maintainability and extensibility All translates to cutting development costs Developing and maintaining large projects in C is difficult
37
Object Oriented Programming (OOP) C, Pascal and a bunch of other languages are procedural languages Procedural languages tend to produce spaghetti code Objects describe the real world better Real world objects share two characteristics: state and behavior Bicycles have state: current gear, number of gears etc. Bicycles have behavior: braking, accelerating, changing gears etc.
38
Object Oriented Programming In software objects are a bundle of state and behavior State is stored in variables Behavior is implemented with methods The benefit of Object Oriented Programming (OOP) is that you can more easily represent real world objects using software objects
39
Object Oriented Programming Modularity Objects source-code is maintained independently of other objects An object can be passed around in the system and it will still work Information hiding An object has a public interface for others to communicate with it Yet, it can maintain private information that is not essential to using it Black-Box: You don’t need to understand the gear mechanism of your bikes to use it
40
Object Oriented Programming Encapsulation Packaging objects variables within a protective custody of methods However, sometimes it is useful expose some of the inner workings of an objects
41
Object Oriented Programming (OOP) Here’s a C++ example of our bicycles class Bicycle { public: // Constructor for a bicycle object Bicycle(int numGears, tGears currGear = GEAR1); // Break to a stop void break(); // Slowdown void slowdown(double targetSpeed); double getCurrentSpeed(); tGear getCurrentGear(); private: int m_numGears; tGears m_currGear; … class Bicycle { public: // Constructor for a bicycle object Bicycle(int numGears, tGears currGear = GEAR1); // Break to a stop void break(); // Slowdown void slowdown(double targetSpeed); double getCurrentSpeed(); tGear getCurrentGear(); private: int m_numGears; tGears m_currGear; …
42
Object Oriented Programming A single object by itself is not very useful An object appears as a component of a larger program with many other objects The interaction between the objects achieves the complex, high-order functionality. Objects interact by invoking each others methods You object might interact with YourBicycle object by invoking its changeGears method.
43
A Few Words About Design Design is something you do when your brain can’t hold the entire project Managing complexity by splitting big projects/problems into manageable chunks (that do fit your brain) Design methods provide the framework and language that allows to store and communicate decisions
44
Object Oriented Design (OOD) OOD is modeling a problem using objects. A key tool in managing complexity is abstraction Elimination of the irrelevant Example: You can teach someone to drive any car by teaching the essentials (steering wheel, ignition) and ignoring the details (particular engine, how fuel is pumped)
45
Object Oriented Design (OOD) Real problems usually have levels of abstraction Car users can see the car at a high level of abstraction However mechanics need to work at a lower level of abstraction (higher detail) Yet, the mechanics too don’t see all the details For example, they may test the battery without caring that’s inside there’s a complex chemical reaction going on
46
Object Oriented Design (OOD) In software it abstraction looks something like this:
47
Object Oriented Design (OOD) OOD is the process of modeling a problem using objects Define the interaction between objects And between levels of abstraction To aid the process – there are ready made solutions for various types of problems called “Design Patterns”
48
Buzz Words Overview Java Write once run anywhere Virtual machine technology Garbage collection and easy memory management JIT (Just In Time compilation) .NET framework Write once use anywhere Common virtual machine to different languages C# is the leading language
49
Buzz Words Overview UML Modeling language for OOD Very popular Desing Patterns Set of ready made design solutions for reoccurring problems RMI, CORBA and Remoting Remote method invocation – calling a method of an object that resides on a remote machine
50
Project Development Lifecycle Project times is measured in years Many models for project development Contract model, extreme programming etc.. In the contract model: Step 1: Gather requirements in the clients language Step 2: Translate into software engineering requirements (SRD) Step 2: Design documents (SDD) – if big projects there may be many levels of abstractions Step 3: Coding (usually no more the 20-30% of the projects time) Step 4: Builds and testing Step 5: Deployments
51
The End
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.