Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding C Data Types and Variables

Tech May 18 3

Data Types in C

C provides a rich set of data types to represent various kinds of information. Integer types handle whole numbers, character types handle individual characters, and floating-point types handle decimal values. A "type" defines the common characteristics of related data, and the compiler needs to know the type to determine how to manipulate the data.

Let's examine all the data types C has to offer.

Determining Type Sizes

The sizeof operator is a keyword that calculates the memory size of a type, expression, or varible in bytes. It's evaluated at compile time rather than runtime.

Key points about sizeof:

  • The expression inside sizeof is not actually evaluated; only its type determines the result
  • The return type of sizeof is size_t
  • On different systems, size_t may be unsigned int or unsigned long long
#include <stdio.h>
int main()
{
    printf("%zd\n", sizeof(char));
    printf("%zd\n", sizeof(_Bool));
    printf("%zd\n", sizeof(short));
    printf("%zd\n", sizeof(int));
    printf("%zd\n", sizeof(long));
    printf("%zd\n", sizeof(long long));
    printf("%zd\n", sizeof(float));
    printf("%zd\n", sizeof(double));
    printf("%zd\n", sizeof(long double));
    return 0;
}

Typical output on a 64-bit system:

  • char: 1
  • _Bool: 1
  • short: 2
  • int: 4
  • long: 4
  • long long: 8
  • float: 4
  • double: 8
  • long double: 8

Expression Evaluation in sizeof

#include <stdio.h>
int main()
{
    short budget = 2;
    int counter = 10;
    printf("%d\n", sizeof(budget = counter + 1));
    printf("budget = %d\n", budget);
    return 0;
}

The expression budget = counter + 1 never executes. During compilation, sizeof determines the result based on the type of budget, which is short. The actual assignment happens at runtime, but sizeof is already resolved during compilation, so the variable remains unchanged.

Variables

Variable Scope

Variables declared outside any code block are global variables. They remain accessible throughout the entire program and can be used by any function.

Variables declared inside a code block (within braces) are local variables. Their visibility is limited to the enclosing block where they're defined.

When a local variable shares the same name as a global variable, the local variable takes precedance within its scope.

#include <stdio.h>
int global_count = 1000;
int main()
{
    int global_count = 10;
    printf("%d\n", global_count);  // outputs 10
    return 0;
}

In this example, the local global_count shadows the global variable when accessed inside main().

Memory Storage Locations

C organizes memory into three main regions:

Variable Type Memory Region
Local variables Stack
Global variables Static/bss
Dynamically allocated Heap

Local variables reside on the stack, global variables live in the static region, and the heap manages dynamically allocated memory through functions we'll cover later.

Input and Output Functions

printf

The printf() function outputs formatted text to the console. The "f" stands for "format," indicating its ability to format output with placeholders.

Format Specifiers

Format specifiers begin with % and indicate how values should be displayed:

Specifier Description
%a Hexadecimal floating-point (lowercase)
%A Hexadecimal floating-point (uppercase)
%c Character
%d Decimal integer (int)
%e Scientific notation (lowercase exponent)
%E Scientific notation (uppercase exponent)
%i Integer (equivalent to %d)
%f Floating-point (float uses %f, double uses %lf)
%g Compact floating-point, up to 6 significant digits
%G Same as %g with uppercase E
%hd Short int in decimal
%ho Short int in octal
%hx Short int in hexadecimal
%hu Unsigned short int
%ld Long int in decimal
%lo Long int in octal
%lx Long int in hexadecimal
%lu Unsigned long int
%lld Long long int in decimal
%llo Long long int in octal
%llx Long long int in hexadecimal
%llu Unsigned long long int
%Le Long double in scientific notation
%Lf Long double
%n Stores count of characters printed so far
%o Octal integer
%p Pointer address
%s String
%u Unsigned integer
%x Hexadecimal integer
%zd size_t type
%% Literal percent sign

Width Control

You can specify minimum field widths:

printf("%5d\n", 123);  // outputs "  123"

This ensures the output occupies at least 5 characters. By default, values are right-aligned with leading spaces. Add a - after % for left-alignment.

For floating-point numbers, the width applies to the entire output:

printf("%12f\n", 123.45);  // outputs "     123.450000" (2 leading spaces)

Since printf displays 6 decimal places by default for floats, 123.45 becomes 123.450000, requiring 2 leading spaces to reach 12 characters.

Precision Control

Control decimal places with .N notation:

printf("Result: %.2f\n", 0.5);   // outputs "Result: 0.50"
printf("Result: %.3f\n", 0.5);   // outputs "Result: 0.500"

scanf

The scanf() function reads formatted input from standard input. Execution pauses until the user provides input and presses Enter. The function then parses the input according to the format string and stores values in the specified variables.

The functon is declared in <stdio.h> and follows a syntax similar to printf().

scanf() automatically skips whitespace characters (spaces, tabs, newlines) when processing numeric format specifiers.

Input parsing resumes from where the previous scanf() call left off, continuing until either the buffer is exhausted or a character that doesn't match the expected format is encountered.

Consider input: -13.45e12# 0

int x;
float y;

scanf("%d", &x);
printf("%d\n", x);

scanf("%f", &y);
printf("%f\n", y);

The first scanf() with %d ignores leading whitespace, then reads from the - character and stops at . (not a valid integer character). Result: x = -13.

The second scanf() with %f continues from ., reading .45e12 as valid scientific notation (a dot followed by digits is valid for floats). The # is not a floating-point character, so parsing stops there. Result: y = 0.4512e12.

Note that scanf() requires the & operator before variable names to pass their memory addresses.

Related Articles

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.