Using the C language how would I write a dynamic array for incoming data

Joseph RW 105 Reputation points
2025-09-19T11:12:33.8366667+00:00

Hi Microsoft team, I need to write a Dynamic array for Data that's coming in on the serial port from an Arduino microcontroller, any advice on How I could do this with this code, I need to send that data for further processing. This code just logs data to the terminal, but I need to send it off for further processing by another application, I was thinking of storing the data in a dynamic array that will increase in size as the data comes in is this even a good idea and is it possible to do this with the Threadpool API

#include <windows.h>
#include <stdio.h>
// Context struct to pass to threadpool callback
typedef struct {
    HANDLE hCom;          // Serial port handle
    PTP_IO pIo;           // Threadpool I/O object
    BYTE buffer[256];     // Buffer for serial data
    DWORD dwRead;         // Bytes read
    OVERLAPPED overlapped; // Overlapped structure
    BOOL waitingOnRead;   // Flag for read state
} SerialContext;
// Threadpool I/O completion callback
VOID CALLBACK SerialIoCallback(
    PTP_CALLBACK_INSTANCE Instance,
    PVOID Context,
    PVOID Overlapped,
    ULONG IoResult,
    ULONG_PTR NumberOfBytesTransferred,
    PTP_IO Io
) {
    UNREFERENCED_PARAMETER(Instance);
    SerialContext* ctx = (SerialContext*)Context;
    if (IoResult != NO_ERROR) {
        printf("I/O error: %lu (Bytes: %lu)\n", IoResult, NumberOfBytesTransferred);
        return;
    }
    if (NumberOfBytesTransferred > 0) {
        ctx->buffer[NumberOfBytesTransferred] = '\0'; // Null-terminate
        printf("Received: %s", ctx->buffer);          // Print ASCII data
    }
    // Restart async read
    ZeroMemory(&ctx->overlapped, sizeof(OVERLAPPED));
    ctx->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (ctx->overlapped.hEvent == NULL) {
        printf("CreateEvent failed: %lu\n", GetLastError());
        return;
    }
    StartThreadpoolIo(ctx->pIo);
    if (!ReadFile(ctx->hCom, ctx->buffer, sizeof(ctx->buffer) - 1, NULL, &ctx->overlapped)) {
        if (GetLastError() != ERROR_IO_PENDING) {
            printf("ReadFile failed: %lu\n", GetLastError());
            CancelThreadpoolIo(ctx->pIo);
            CloseHandle(ctx->overlapped.hEvent);
        }
    }
}
int main() {
    // Initialize context
    SerialContext ctx = { 0 };
    ctx.waitingOnRead = FALSE;
    // Open serial port
    ctx.hCom = CreateFile(
        L"\\\\.\\COM7", // Adjust COM port as needed
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,
        NULL
    );
    if (ctx.hCom == INVALID_HANDLE_VALUE) {
        printf("CreateFile failed: %lu\n", GetLastError());
        return 1;
    }
    // Configure DCB
    DCB dcb = { 0 };
    dcb.DCBlength = sizeof(dcb);
    if (!GetCommState(ctx.hCom, &dcb)) {
        printf("GetCommState failed: %lu\n", GetLastError());
        CloseHandle(ctx.hCom);
        return 1;
    }
    dcb.BaudRate = CBR_9600;
    dcb.ByteSize = 8;
    dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;
    dcb.fDtrControl = DTR_CONTROL_ENABLE;
    if (!SetCommState(ctx.hCom, &dcb)) {
        printf("SetCommState failed: %lu\n", GetLastError());
        CloseHandle(ctx.hCom);
        return 1;
    }
    // Set timeouts
    COMMTIMEOUTS timeouts = { 0 };
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    if (!SetCommTimeouts(ctx.hCom, &timeouts)) {
        printf("SetCommTimeouts failed: %lu\n", GetLastError());
        CloseHandle(ctx.hCom);
        return 1;
    }
    // Purge stale data
    if (!PurgeComm(ctx.hCom, PURGE_RXCLEAR | PURGE_RXABORT)) {
        printf("PurgeComm failed: %lu\n", GetLastError());
        CloseHandle(ctx.hCom);
        return 1;
    }
    // Create threadpool I/O
    ctx.pIo = CreateThreadpoolIo(ctx.hCom, SerialIoCallback, &ctx, NULL);
    if (ctx.pIo == NULL) {
        printf("CreateThreadpoolIo failed: %lu\n", GetLastError());
        CloseHandle(ctx.hCom);
        return 1;
    }
    // Initialize OVERLAPPED
    ZeroMemory(&ctx.overlapped, sizeof(OVERLAPPED));
    ctx.overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (ctx.overlapped.hEvent == NULL) {
        printf("CreateEvent failed: %lu\n", GetLastError());
        CloseThreadpoolIo(ctx.pIo);
        CloseHandle(ctx.hCom);
        return 1;
    }
    // Start first read
    StartThreadpoolIo(ctx.pIo);
    if (!ReadFile(ctx.hCom, ctx.buffer, sizeof(ctx.buffer) - 1, NULL, &ctx.overlapped)) {
        if (GetLastError() != ERROR_IO_PENDING) {
            printf("ReadFile failed: %lu\n", GetLastError());
            CancelThreadpoolIo(ctx.pIo);
            CloseHandle(ctx.overlapped.hEvent);
            CloseThreadpoolIo(ctx.pIo);
            CloseHandle(ctx.hCom);
            return 1;
        }
    }
    printf("Serial reader started. Press Ctrl+C to exit.\n");
    // Main loop to keep program alive
    while (1) {
        Sleep(1000); // Keep main thread alive; callbacks handle I/O
    }
    // Cleanup (unreachable due to loop, but for completeness)
    CancelThreadpoolIo(ctx.pIo);
    WaitForThreadpoolIoCallbacks(ctx.pIo, FALSE);
    CloseThreadpoolIo(ctx.pIo);
    CloseHandle(ctx.overlapped.hEvent);
    CloseHandle(ctx.hCom);
    return 0;
}
Developer technologies | C++
Developer technologies | C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
{count} votes

1 answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 81,616 Reputation points Volunteer Moderator
    2025-09-24T16:10:56.66+00:00

    your buffer is a inline array in the context structure. it can not be expanded dynamically. you would need to change it to a *BYTE pointer and malloc() to allocate the buffer. you would also need to store the size somewhere. when the buffer was full, you would allocate a larger buffer, copy the old buffer contents to the new buffer and update pointer, and release old buffer. if you changed context to:

    typedef struct {
        HANDLE hCom;          // Serial port handle
        PTP_IO pIo;           // Threadpool I/O object
        *BYTE buffer;         // Buffer for serial data
        int bufferSize;       // size of buffer
        DWORD dwRead;         // Bytes read
        OVERLAPPED overlapped; // Overlapped structure
        BOOL waitingOnRead;   // Flag for read state
    } SerialContext;
    
    int resizeBuffer(*SerialContext ctx, int newSize)
    {
       if (ctx->buffer == 0) {
          ctx->buffer = (*BYTE) malloc(newSize);
          ctx->buffer[0] = 0;
          ctx->bufferSize = newSize; 
          return 0;
       }
    
       if (strlen(ctx->buffer) >= newSize)
          return 1;
    
       *BYTE newBuffer = (*BYTE) malloc(newSize);
       strcpy(newBuffer, ctx->buffer);
       free(ctx->buffer);
       ctx->buffer = newBuffer;  
       ctx->bufferSize = newSize; 
       return 0;
    }
    
    ...
    
      SerialContext ctx = { 0 };
      resizeBuffer(&ctx);
    
    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.