Overview
Conditional Operator (?:)
-
Definition: A ternary operator that evaluates a condition and returns one of two values based on whether the condition is truthy or falsey
-
Syntax:
condition ? value_if_true : value_if_false -
Key Characteristic: The conditional operator is an expression, not a control flow statement. It produces a value that can be used in larger expressions
-
Common Misuse: Treating
?:as a shorthandif/elseby performing actions within the operator// INCORRECT - treats ?: like if/else
(number > 0) ? printf("positive\n") : printf("not positive\n");
// CORRECT - uses ?: as an expression
printf("%d is %s\n", number, (number > 0) ? "positive" : "not positive"); -
Appropriate Use Cases:
- Assigning one of two values to a variable
- Passing one of two values as a function argument
- Returning one of two values from a function
- Any situation where the result of the operator is used, not discarded
-
Advantage: Can make simple conditional assignments more concise and readable
-
Disadvantage: Complex nested conditionals become difficult to read;
if/elseis clearer in such cases
Switch Statements
- Definition: A control flow statement that performs value-based selection by matching an expression against multiple
caselabels - Syntax:
switch(expression)
{
case value1:
// statements
break;
case value2:
// statements
break;
default:
// statements
} - Expression Requirements: The expression must be an integral type (int, char, etc.); complex boolean operations (
>,<,>=,<=) are not supported - Case Labels: Each
caselabel must be a constant value; multiple cases can precede the same statements - Break Statement: Terminates the switch block; without
break, execution continues to the next case (fall-through behavior)switch(rank)
{
case 1:
printf("A\n");
break; // execution stops here
case 11:
printf("J\n");
break;
default:
printf("%d\n", rank);
} - Default Case: Optional; executes if no
casematches the expression - Fall-Through: If
breakis omitted, execution continues into the next case; this is sometimes intentional but often a source of bugsswitch(day)
{
case 1:
case 2:
case 3:
printf("Weekday\n"); // executes for cases 1, 2, or 3
break;
case 6:
case 7:
printf("Weekend\n");
break;
} - Advantages:
- More readable than long
if/else if/elsechains for value matching - Efficient for matching against many discrete values
- Clear intent when checking a single expression against multiple values
- More readable than long
- Disadvantages:
- Cannot handle range checks or complex conditions
- Fall-through behavior can introduce subtle bugs if
breakis forgotten - Less flexible than
if/elsefor non-equality comparisons
Pointers and Arrays
- Fundamental Relationship: The name of an array is a pointer to the first element of that array
int myArray[10];
// myArray resolves to &myArray[0] - Array and Pointer Parameter Equivalence: In function parameters, array notation and pointer notation are interchangeable
// These two declarations are equivalent:
void someFunction(int array[], int used);
void someFunction(int* array, int used); - Implication: An array can be passed to a function expecting a pointer, and vice versa
- String Functions: Library functions like
strlen()acceptconst char*parameters because strings are character arrayssize_t strlen(const char* str);
// Can be called with: strlen(myCharArray);
sizeof() Operator
- Definition: An operator (not a function) that returns the size in bytes of a type or variable
- Behavior on Locally-Declared Arrays: Returns the total size of the array in bytes
char mystr[100];
int size = sizeof(mystr); // Returns 100 (size of entire array) - Behavior on Array Parameters: When an array is passed to a function, it decays to a pointer;
sizeof()returns the size of a pointer, not the arrayvoid checkSize(char mystr[])
{
int size = sizeof(mystr); // Returns size of pointer (typically 4 or 8 bytes)
// NOT the size of the original array!
} - Critical Limitation:
sizeof()cannot reliably determine array capacity when the array is passed as a function parameter - Correct Usage: Use
sizeof()only on locally-declared arrays or when you know the exact type and size - Best Practice: Pass array capacity as a separate parameter rather than relying on
sizeof()// CORRECT approach
void processArray(int array[], int capacity)
{
// capacity is passed explicitly
} - Common Pitfall: Attempting to use
sizeof()to calculate the number of elements in an array parameter// WRONG - will not work as intended
int numElements = sizeof(array) / sizeof(array[0]); // in a function parameter