Showing posts with label C_Q&A. Show all posts
Showing posts with label C_Q&A. Show all posts

Thursday, July 23, 2026

Beyond the Atmosphere: Why C and C++ Remain the Foundation of NASA’s Mission-Critical Systems

Beyond the Atmosphere: Why C and C++ Remain the Foundation of NASA’s Mission-Critical Systems

The High-Stakes Environment of Spaceborne Software

In the realm of space exploration, software does not reside in the forgiving climate of a temperature-controlled data center. Instead, it operates in a hostile vacuum bombarded by high-energy cosmic radiation, where power budgets are measured in milliwatts and hardware must be "radiation-hardened" to survive. At NASA, software development is defined as hard real-time embedded engineering rather than typical cloud computing. In this environment, a system cannot simply be "rebooted" if a race condition or memory leak occurs during a terminal descent sequence or a critical thruster burn.

The NASA software landscape is vast and uncompromising, spanning spacecraft flight computers, autonomous rover navigation, satellite attitude control, and life-support systems. In these domains, the margin for error is non-existent. A software "bug" is not a mere ticket in a backlog; it is a potential total mission failure. This unforgiving reality necessitates the absolute transparency and deterministic control offered by C and C++.

The Core Philosophy: Deterministic Performance vs. High-Level Convenience

For a Flight Software Architect, the strategic priority is always Predictability > Convenience. We require deterministic behavior, meaning the software must execute with mathematically provable timing and no runtime surprises. High-level languages frequently trade this predictability for developer ease—a trade-off that is technically unacceptable for flight-critical systems.

Feature

Status in NASA Flight Code

Technical Impact on Mission

Garbage Collection

Forbidden

Causes non-deterministic timing and unpredictable CPU pauses.

JIT Compilation

Forbidden

Introduces unpredictable runtime behavior and execution jitter.

Hidden Memory Allocation

Forbidden

Risks heap fragmentation and sudden, non-recoverable system crashes.

This philosophy ensures that every machine instruction is accounted for. While modern frameworks offer layers of abstraction, space exploration requires directness. Rockets do not care about "clean" high-level abstractions; they require absolute temporal and logic correctness.

Direct Hardware Control and Resource Optimization

Spaceborne hardware is significantly constrained compared to consumer-grade silicon. Radiation-hardened CPUs are often generations behind—relying on larger transistor nodes to ensure stability—which means they lack the clock cycles to handle the overhead of modern "safe" languages. To ensure efficient operations, we frequently utilize a Real-Time Operating System (RTOS) such as RTEMS (Real-Time Executive for Multiprocessor Systems), which provides the deterministic scheduling required for C-based flight code.

  • Low-Level Hardware Access: C and C++ allow us to manipulate memory-mapped registers and hardware peripherals directly. This is essential for controlling actuators, sensors, and propulsion units with surgical precision.
  • Minimal Runtime Overhead: These languages produce small, efficient binaries that fit within the strict Flash and RAM limits of flight hardware. Without a Virtual Machine (VM) or heavy interpreter, every cycle is dedicated to the mission.
  • Manual Memory Management: By utilizing static allocation and memory pools, we eliminate the risk of heap fragmentation.

In this context, Fine-Grained Control is the primary objective. High execution speed is a secondary "bonus" consequence; the ability to dictate exactly how every byte of memory is laid out and how every CPU cycle is spent is what ensures the mission’s survival.

The Ironclad Rulebook: NASA’s Coding Standards and Safety Protocols

NASA does not employ "casual C." Every line of code is governed by the strategic application of formal verification and strict coding standards, specifically MISRA-C and the JPL Coding Standard. These protocols strip away the "dangerous" flexibility of the languages to ensure safety.

Prohibited Practices and Engineering Rationales:

  • No Dynamic Memory: All memory must be allocated at startup. This prevents heap-related failures or fragmentation during a mission that could last decades.
  • No Recursion: We ban recursion because we must mathematically prove the maximum stack depth before launch. Recursion makes that proof non-deterministic and risks stack overflow.
  • No Function Pointers: These complicate execution flow and make static analysis difficult; we require a predictable, traceable path for every instruction.
  • No Implicit Casting: To prevent data loss or type-mismatch errors that could lead to logic failures.
  • Mandatory Initialization: Every variable must be initialized to ensure no "garbage" values influence flight logic.

For life-critical systems, NASA also maintains heritage in Ada, a language designed for high-integrity environments. Ada's strong type system and built-in support for concurrency complement the C/C++ ecosystem in systems where error detection must be baked into the compiler.

Proven Heritage: From HAL/S to the Core Flight System (cFS)

The "heritage" factor is a cornerstone of aerospace engineering. When a mission is designed to last 40 years, we rely on a lineage of proven code.

  • HAL/S (High-order Assembly Language/Shuttle): This specialized language was the backbone of the Space Shuttle, providing the early standard for aerospace-specific safety.
  • Legacy and Transition: While the 1977 Voyager probes primarily utilize custom Assembly for their three onboard computers, the industry transitioned to C for standardization in modern deep-space heritage.
  • Mars Rovers: Rovers like Perseverance utilize C and C++ to manage real-time sensor fusion and autonomous navigation via RTEMS.
  • Core Flight System (cFS): NASA’s cFS is an open-source, modular flight software framework written in C. It provides task scheduling and telemetry, serving as the trusted foundation for a majority of modern NASA missions.

The Polyglot Mission: Ground Systems and Data Ecosystems

While C/C++ dominate the flight computer, a modern mission requires a tiered language strategy. We distinguish strictly between Flight Code (onboard) and Ground Code (on Earth).

Strategic Role Allocation:

  • Python: The "King of Space Data." We use Python for ground-based data analysis and mission planning. Frameworks like AstroPy handle celestial coordinate transformations, while OpenMDAO is used for multidisciplinary design optimization of structured systems.
  • MATLAB/Simulink: Essential for Model-Based Design. Engineers use Simulink to simulate attitude control and trajectory optimization before using an "Embedded Coder" to generate the C code that actually flies.
  • Fortran: Continues to shine in high-performance scientific computing (HPC). It remains the industry standard for climate modeling and complex fluid dynamics for rocket propulsion.
  • Java: Used for building interactive systems and user interfaces for mission control, leveraging its platform independence to operate across various ground-station OS environments.

Emerging Frontiers: Rust, Julia, and F Prime (F´)

As missions evolve, NASA evaluates modern languages that address memory safety and high-speed simulation.

  • Rust: NASA is exploring Rust for its "Ownership" model, which provides memory safety without garbage collection. It has the potential to eliminate entire classes of memory-related vulnerabilities in future secure embedded applications.
  • Julia: This language is gaining interest for complex mathematical modeling. It offers the high-level ease of Python with C-like execution speed, making it ideal for modeling weather and orbital mechanics.
  • F Prime (F´): Developed by JPL, F´ is a modular flight software framework. While the core is C++, it leverages Python for modeling and testing, representing the future of modular, component-based flight software for CubeSats and deep-space probes.

Conclusion: The Enduring Dominance of Precision

NASA’s reliance on C and C++ is a strategic decision rooted in the physical realities of space and a philosophy of absolute mission success. These tools remain the foundation because they align with the fundamental requirements of spaceborne architecture.

Three Reasons C and C++ Remain Indispensable:

  1. Control: Absolute authority over hardware-level registers and memory layout.
  2. Predictability: Deterministic execution that allows for formal mathematical verification.
  3. Proven Reliability: Decades of flight heritage from the Shuttle era to the surface of Mars.

For all 2026 published articles list: click here

...till the next post, bye-bye & take care

Monday, April 27, 2026

Navigating the Unknown: A Student’s Guide to Reading Unfamiliar Code

Navigating the Unknown: A Student’s Guide to Reading Unfamiliar Code

Introduction: The Mental Shift

Faced with thousands of lines of "someone else’s code" spread across hundreds of files, it is natural to feel a sense of overwhelm. You might find yourself criticizing the style or architecture, imagining that if it were only written your way, it would be "easier" to grasp. However, as a mentor, I must tell you that the core difficulty is rarely a failure of the original author or a lack of your own skill; it is simply a lack of a mental model.

When you read your own code, the map of connections already exists in your mind. With unfamiliar code, that map is missing. To build it, you must shift your perspective from critic to explorer:

"Approach code without judgment, with the purpose of understanding, not evaluating."

By setting aside stylistic preferences, you clear the cognitive space required for deep learning. Before we begin pulling on the threads of the logic, however, we must ensure your environment is configured for active exploration.

--------------------------------------------------------------------------------

Preparation: Setting the Stage for Exploration

Diving into a complex codebase without the right tools is like navigating a dense forest in the dark. To gain the confidence needed for effective discovery, you must move the code from a static set of text files into a living, observable system.

Tool/Action

Primary Purpose

Benefit for the Learner

"Smart" IDE

Indexes the codebase for navigation (jumping to definitions, finding usages).

Allows you to trace connections instantly without losing your place in the file structure.

Building and Running

Validates the environment and allows for runtime observation via a debugger.

Confirms the code is functional and provides a "live" look at how data actually flows.

Local Git Repository

Initializing a baseline (git init .; git add *; git commit -m "Baseline").

Creates a "safe zone" for fearless experimentation; you can revert any "discovery change" instantly.

Once your environment is stable and you can execute the program at will, you need a strategic entry point to begin your investigation.

--------------------------------------------------------------------------------

Strategy: Finding the End of the Thread

Code is non-linear; it is rarely meant to be read from file one to file one hundred. Think of it as many tangled balls of yarn on the floor. To make sense of it, you must find an interesting "end" and pull.

The Power of "Grepping"

To find where execution begins for a specific feature, use your IDE's global search (often called "grepping") for external markers. Search for:

  • GUI Elements: Visible text found on buttons, labels, or menu headers.
  • Command Line Options: Flags (e.g., --verbose) used to launch the program.
  • Error Messages: Specific strings that appear when the system fails.
  • Input and Focus Events: Keyboard or mouse event handlers that reveal how the application integrates with the underlying platform.

Following the Button

In a GUI-driven application, "Following the Button" is a premier tactic for building a mental map:

  1. The Two-Step Search: Search for the button's text. In localized codebases, this string will lead you to a localization mapping file. From there, you must find the Constant associated with that string, and then search for that constant in the source code to find the actual widget definition.
  2. Locate the Handler: Identify the onClick handler or the specific function tied to that widget's action.
  3. Set a Breakpoint: Pause execution in the debugger when the button is clicked.
  4. Analyze the Stack Trace: Look at the stack trace to see the path from the "main" loop to this specific handler. This reveals the dispatching mechanism of the entire framework.
  5. Map the Object Tree: Use the debugger to traverse "parent" relationships. This helps you understand the widget hierarchy—a structure similar to a DOM tree—which reveals how the UI is logically organized.

Once you have identified how the user interface triggers specific actions, the next logical step is to see how the system validates its own internal logic.

--------------------------------------------------------------------------------

Using Tests as Runnable Documentation

Traditional documentation is often outdated or missing, but tests represent the author's intent in a way that must remain compatible with the code. Integration and system tests are particularly valuable for new developers because they demonstrate the system’s "boundaries."

Runnable Documentation: This term describes tests that serve as functional examples of how to initialize the system, which access points are primary, and which use cases were prioritized by the authors.

As you form hypotheses about how the code works, use the test suite to verify them:

  • Discovery Refactoring: Write new tests or modify existing ones to see if the code behaves as you expect.
  • Pro-Tip: Treat this as "discovery code." Be prepared to delete these tests once you understand the logic. Deleting discovery code is vital; it prevents you from falling into the sunk cost fallacy, where you try to force a codebase to fit an initial (and likely incorrect) mental model simply because you spent time writing code for it.

While tests show how a system should work, reading the entry point of the program shows how it actually initializes its backbone.

--------------------------------------------------------------------------------

Mapping the Big Players: Reading "Main" and Classes

To gain a high-level architectural view, you must find the "Main-like" function—the driver of the module or program.

Identifying the "Big Players"

Read the "Main" function from top to bottom, focusing on the cardinality of the objects created.

  • The Engine: Look for "Big Players"—objects created at startup that last the lifetime of the program. If only one or two instances of a class are created (Singletons or Managers), they likely represent the architectural backbone.
  • The Anchors: Identify "Has-a" relationships. These objects hold onto other components and serve as the central anchors for your mental map.
  • The Context: Note which objects are passed into almost every function call; these represent the "Context" or "State" of the application.

Strategy Checklist for Reading a Class

When your investigation narrows to a specific class, use this checklist to decode its role:

  • Study Inheritance and Interfaces first: This reveals the "contract"—how the rest of the system is forced to view this class.
  • Grep for Includes/Imports: See which files rely on this class to understand its "neighborhood" and influence.
  • Analyze Public Functions: Treat the public API as the "command interface." Private functions are usually just implementation details; don't get bogged down in them until you understand the public commands.

After the technical reading of files is complete, the final step is to move that knowledge from the screen into your long-term memory.

--------------------------------------------------------------------------------

Solidifying Understanding: Refactoring and Rubber Ducking

Learning is best achieved through action. "Discovery Refactoring"—changing names, extracting methods, or simplifying logic—forces you to engage with the code. However, avoid "style-guided refactorings" that focus on aesthetics; these can make you arrogant and blind to the original constraints that forced the author to write the code a certain way.

The Retelling Process

To ensure your mental model is robust, move beyond "Rubber Ducking" (talking to an object) and engage in a social retelling:

  1. Synthesize Notes: Compile your diagrams and debugger traces into a cohesive story.
  2. Explain the Logic: Try to explain a feature's flow to a colleague or write it as a fictional blog post.
  3. Identify Gaps: The social pressure to be clear to another human will immediately highlight "fuzzy" areas in your understanding where your mental model is incomplete.

Explaining to a real person prevents you from glossing over details, ensuring that your discovery code serves its purpose before it is deleted.

--------------------------------------------------------------------------------

Conclusion: Embracing the Snapshot in Time

Mastering the art of reading code is ultimately an exercise in professional empathy. As you navigate these files, remember to maintain the "Compassionate Programmer" mindset. Every codebase is a snapshot in time—a reflection of a specific moment where requirements were changing, plans were unfinished, and deadlines were looming.

Diverse coding styles are not obstacles; they are opportunities to see how different minds solve the same fundamental problems. Approach the work with kindness toward those who came before you, and you will find that the code begins to speak back.

For all 2026 published articles list: click here

...till the next post, bye-bye & take care

Sunday, April 26, 2026

Stop Reading Code Like a Novel: 4 "Spoiler" Techniques for Instant Understanding

Stop Reading Code Like a Novel: 4 "Spoiler" Techniques for Instant Understanding

We’ve all been there: staring down a 500-line legacy function that feels like it was written to keep secrets rather than solve problems. Our natural instinct is to start at line one and read sequentially, just like we were taught in school. But here is the hard truth: reading a complex function "cover to cover" is a trap. It is slow, it is exhausting, and it’s often the least effective way to actually understand what is happening.

To master legacy systems, you need to shift your approach. We are going to stop being passive readers and start performing an Inspectional Reading. The goal isn’t to savor every line; it’s to gain maximum knowledge in minimum time.

The Non-Fiction Mindset: Skimming is a Superpower

We’ve been told since childhood that skimming is a shortcut or a sign of laziness. In software engineering, I’m telling you it is a professional superpower.

Source code is not a mystery novel. You aren't reading it for the prose or the plot twists; you’re reading it to acquire knowledge. Source code is non-fiction. When you approach a function, your Inspectional Reading should have two immediate goals:

  1. Determine Relevance: Is this code even responsible for the bug or feature you’re working on?
  2. Identify the Main Message: What is the high-level intent before you get bogged down in the implementation details?

"Source code is read for knowledge and understanding. Like non-fiction books. For this reason, you don't want to start by reading a function ‘cover to cover’."

Get the Spoiler: Start at the End

If a function is a story, you need to know how it ends before you care about how it began.

Step Zero: Orient with the Signature

Before you even look at the function body, look at the name, the parameters, and the return type. If the function is well-named (e.g., calculateMonthlyTax), your inspectional reading becomes a confirmation mission rather than a discovery mission. This "Step Zero" orients your brain so you know exactly what to look for once you dive in.

Step One: Find the "Protagonist"

Once you’re inside, skip straight to the last line. The logic of any function is a journey toward its output. By finding the "spoiler" at the end, you identify the Protagonist of the story.

In a perfect world, this is a clean return statement. However, in the trenches of legacy code, "returns" can be messy. Look for:

  • Explicit Return Values: The return something; at the bottom.
  • Modified Parameters: Outputs passed back through the function’s arguments.
  • Global State: Changes to variables outside the function’s scope.
  • Exceptions: Values "returned" via error-handling channels.

Whatever the form, the object being returned is the point of the function. Know the ending, and the rest of the code starts to make sense.

"Get a big spoiler, skip to the end of the function's story, and start from the last line. It should look like return something."

Spot the "Main Characters" via Frequency

Once you’ve identified the protagonist, you need to find the other Main Characters. In any function, the most important objects or variables are the ones that appear most often.

Don't just count them manually. Use your IDE to your advantage: click a variable to highlight every occurrence within the function.

By looking at the Frequency of these highlights, you can instantly distinguish between:

  • Main Characters: The central objects the function is designed to manipulate (e.g., invoice, userProfile).
  • Secondary Characters: Supporting objects that exist only for a few lines to help with a specific calculation (e.g., tempCounter, i).

This is a life-saver for massive functions. Even if you are only looking at a specific 20-line block in a much larger script, the variables that are highlighted most frequently will tell you what that specific section is actually about.

Filter for the "Main Action"

Not every line of code is created equal. To understand a function quickly, you must learn to filter out the noise. In every codebase, there is a distinct difference between the "main action" and the "bookkeeping."

  • The Bookkeeping Style: These are secondary quests. They look like if (log.isDebugEnabled()), null checks, input validation, or setting up secondary characters. It’s "administrative" code.
  • The Main Action Style: This is the domain-specific business logic. It looks like calculateInterest(), updateInventory(), or applyDiscount().

The Scanning Technique: Scan the lines rapidly. If a line looks like Bookkeeping, don't dwell on it. Even if you don't fully understand the line, move on. Your "gut feeling" will improve with practice. You are looking for the lines that actually move the protagonist toward the ending you found in Section 2.

--------------------------------------------------------------------------------

Pro-Tip: The Second Pass If you reach the end of a function and the "Main Action" still hasn't clicked, don't panic. Perform a second, rapid scan. You'll find it’s much easier the second time because your eyes are now familiar with the "landscape" of the code. The signal will naturally start to stand out from the noise.

--------------------------------------------------------------------------------

Conclusion: Mastering the Inspectional Game

Understanding code is a game of identification and filtration. When you stop being a passive reader and start being an active Inspector, the friction of legacy code begins to melt away. You aren't there to read a story; you’re there to locate the primary objects, identify the conclusion, and filter out the secondary causes.

The next time you open a black-box function, will you start at line one, or will you skip straight to the ending?

For all 2026 published articles list: click here

...till the next post, bye-bye & take care

Saturday, April 25, 2026

Beyond the Scroll: Why Random Access is the Unsung Hero of Modern Programming

Beyond the Scroll: Why Random Access is the Unsung Hero of Modern Programming

Imagine trying to find a single specific sentence in a massive book, but you are forced to read every word from page one until you reach it. This linear frustration was the technical reality of early computing, where data was stored on large reels of magnetic tape. To reach a specific record, the system had to physically wind through the entire tape sequentially.

The transition to modern disks revolutionized programming by enabling random access—the ability to jump directly to any byte in a file. This capability is the silent engine behind every efficient database and modern application. In this post, we will explore the most impactful takeaways for handling files in C and reveal how mastering raw byte streams provides unparalleled control over your data.

Why Binary Files are Actually "Simpler" Than Text

It sounds counter-intuitive to many students, but binary files are significantly easier to manage than text files when implementing random access. In a text file, certain byte values are reserved for control characters that add a layer of complexity for the parser. For example, the value 13 represents a carriage return, 10 is a line feed, and 26 marks the end of a file (EOF).

Software reading text files must constantly monitor and interpret these specific values, whereas a binary file treats every byte as a raw, neutral value. This lack of "special meaning" ensures that what you write is exactly what you get back, without the system interfering with the data stream.

A binary file is a file of any length that holds bytes with values in the range 0 to 255.

By working within this 0–255 range without hidden control characters, developers can treat the file as a clean, predictable stream of information. Modern high-level languages often abstract this further by treating all data as "streams," but the logic remains rooted in these raw binary foundations.

The Art of "Teleporting" Through Data

Random access allows you to move to any part of a file to read or write data without the overhead of traversing the entire file from the beginning. In C, we manage this "teleportation" through navigation tools like fseek and ftell, or their more robust counterparts, fgetpos and fsetpos.

As an educator, I must emphasize that the choice between these pairs is not just stylistic—it is about scalability. While fseek and ftell are common, they rely on standard integers to track file positions, which can lead to overflows in very large files. To build professional-grade applications, you should use fgetpos and fsetpos, which utilize the fpos_t type specifically designed to handle massive file offsets that exceed integer limits.

The Power of the "+"—Deciphering File Mode Combinations

Opening a file in C requires a "mode," and adding a "+" to that mode is a small change that grants massive flexibility by allowing both reading and writing simultaneously. However, you must choose your base mode carefully to avoid accidental data loss. For instance, w+ is destructive; it creates a new file or immediately truncates an existing one to zero length.

In contrast, r+ requires the file to already exist, making it the safer choice for editing existing data. One of the most technically nuanced modes is a+, which opens a file for both reading and appending. This mode is unique because it handles the removal of the EOF marker before writing new data and ensures the marker is restored once the write is complete, maintaining the integrity of the file structure.

The Performance Cost of "Success"

Even helpful feedback can become a bottleneck if it is implemented without considering performance. In many Windows-based examples, you might see a user-defined function like FileSuccess() used to output the success or failure of a file operation along with the filename to the system debugger.

While this is a helpful helper function during the initial development phase, it comes with a hidden cost. Outputting text to a system debugger involves significant overhead that can drastically slow down an application that performs frequent file operations.

It's a little onerous if you are after performance, so you might limit this to debugging.

To maintain high-performance standards, ensure that such system-level messaging is strictly limited to your debugging builds and stripped out before the software reaches production.

The "Index and Data" Architecture

The most powerful application of random access is the "Index and Data" architecture. In this system, you maintain a fixed-size index.dat file containing structs that store the position (fpos_t) and the size of data records. These markers point to variable-length content stored in a separate data.dat file, allowing you to find any specific record almost instantly.

While this technique is the foundational logic beneath sophisticated systems like SQLite and MySQL, it requires a disciplined approach to file management. Some developers attempt to write records to a position far beyond the current end of the file to "reserve" space.

As a best practice, I warn against this: writing to positions beyond the current end of the file is not a good technique and is generally not portable across different operating systems. For reliable software, always build your files sequentially or within the bounds of your established index.

The Nuance of Closing Files (Leaks vs. Losses)

The fclose command is often the most overlooked part of the file lifecycle, yet its misuse carries different risks depending on the operation. If you fail to close a file after a write operation, you face the very real threat of data loss. This is because C uses fixed-sized buffers; data is often held in memory and only "flushed" to the physical disk once the buffer is full or the file is explicitly closed.

On the other hand, failing to close a file after a read operation primarily results in a memory leak. While the data on the disk remains safe, your application continues to consume system resources unnecessarily. This makes fclose the most critical tool for ensuring both the integrity of your data and the stability of the host system.

Conclusion: The Foundation of Modern Data

Even in an era dominated by high-level, inexpensive databases, the fundamental logic of random access remains indispensable. It provides the ultimate "canvas" for data storage, offering a level of precision and flexibility that abstractions simply cannot match.

By mastering these raw streams, you move from being a user of tools to a creator of them. In a world of high-level abstractions, how much more control could you gain by mastering the raw streams of bytes beneath your applications? The ability to read or write anywhere in a binary file is not just a technical feature; it is the absolute foundation of modern data management.

For all 2026 published articles list: click here

...till the next post, bye-bye & take care

Friday, April 10, 2026

Write a program that sorts a given array of names.|| C Lab Program

 WAP_F06: Write a C program that sorts a given array of names.|| Sorting and Searching


WAP_F06: C Lab Program


//Sorts a given array of names.
#include <stdio.h>
#include <string.h>

int main() {
    char names[50][50], temp[50];
    int n, i, j;

    // Input number of names
    printf("Enter number of names: ");
    scanf("%d", &n);

    // Read names
    printf("Enter %d names:\n", n);
    for (i = 0; i < n; i++) {
        scanf("%s", names[i]);  // Reads a single word as name
    }

    // Sorting names using simple string comparison
    for (i = 0; i < n - 1; i++) {
        for (j = i + 1; j < n; j++) {
            if (strcmp(names[i], names[j]) > 0) {
                strcpy(temp, names[i]);
                strcpy(names[i], names[j]);
                strcpy(names[j], temp);
            }
        }
    }

    // Print sorted names
    printf("\nNames in alphabetical order:\n");
    for (i = 0; i < n; i++) {
        printf("%s\n", names[i]);
    }

    return 0;
}



OUTPUT


Enter number of names: 6
Enter 6 names:
Vishnu
Hanuman
Shiva
Krishna
Rama
Ganesha

Names in alphabetical order:
Ganesha
Hanuman
Krishna
Rama
Shiva
Vishnu


For all 2026 published articles list: click here

...till the next post, bye-bye & take care

Thursday, April 9, 2026

Write a program that sorts the given array of integers using insertion sort in ascending order || C Lab Program

 WAP_F05: Write a C program that sorts the given array of integers using insertion sort in ascending order || Sorting and Searching


WAP_F05: C Lab Program


//The given array of integers using insertion sort in ascending order.
#include <stdio.h>

int main() {
    int arr[50], n, i;
    void insertionSort(int [], int );

    // Input number of elements
    printf("Enter number of elements: ");
    scanf("%d", &n);

    // Input array elements
    printf("Enter %d integers:\n", n);
    for (i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
    }

    // Call insertion sort function
    insertionSort(arr, n);

    // Print sorted array
    printf("Array sorted in ascending order:\n");
    for (i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}

// Function to perform insertion sort in ascending order
void insertionSort(int arr[], int n) {
    int i, key, j;

    for (i = 1; i < n; i++) {
        key = arr[i];      // Element to insert
        j = i - 1;

        // Shift elements that are greater than key
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }

        // Insert key at correct location
        arr[j + 1] = key;
    }
}



OUTPUT


Enter number of elements: 9
Enter 9 integers:
4 5 6 1 7 2 8 3 9
Array sorted in ascending order:
1 2 3 4 5 6 7 8 9


For all 2026 published articles list: click here

...till the next post, bye-bye & take care