Hello

I have written my program and right now I am stuck in something that I thought that was going to be easy.

I have the char buffer, which receives from the serial port some letters and 2 numbers at position 3, lenght 2. I want to extract those numbers and place them to an int to make numeric comparisons.

I am quite new at C, in other languages it would have been so easy, but I'm totally stuck in this...

Thanks!

marc

Dani AI

Generated

The serial buffer contains letters with a fixed two-digit number at a known offset (position 3, length 2). The core requirement is to copy exactly that two-character substring, validate it is numeric, and convert it to an integer with range/error checks. was correct that atoi() is brittle for mixed strings; 's sscanf hint and 's manual loop point in the right direction but need bounds checks and validation to be safe in real input handling.

A robust C-style approach: copy the substring into a small temp buffer, NUL-terminate it, confirm the characters are digits (or an optional sign), then call strtol() while checking errno and range.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>

int extract_digits(const char *buf, int pos, int len, int *out) {
    size_t buflen = strlen(buf);
    if (pos < 0 || (size_t)pos + (size_t)len > buflen || len <= 0 || len >= 16) return 0;
    char tmp[16];
    memcpy(tmp, buf + pos, len);
    tmp[len] = '\0';
    for (char *p = tmp; *p; ++p) {
        if (!isdigit((unsigned char)*p) && !(*p == '+' || *p == '-')) return 0;
    }
    errno = 0;
    long v = strtol(tmp, NULL, 10);
    if (errno == ERANGE || v < INT_MIN || v > INT_MAX) return 0;
    *out = (int)v;
    return 1;
}

A modern C++ option (no allocation, no exceptions) uses std::from_chars for a fast, locale-independent parse:

#include <charconv>
#include <string>

bool extract_digits_cpp(const std::string &s, size_t pos, size_t len, int &out) {
    if (pos + len > s.size() || len == 0) return false;
    const char *begin = s.data() + pos;
    int val = 0;
    auto res = std::from_chars(begin, begin + len, val);
    if (res.ec == std::errc() && res.ptr == begin + len) { out = val; return true; }
    return false;
}

Notes: confirm whether "position 3" is zero-based or one-based before indexing; ensure the serial read either NUL-terminates the buffer or use the returned byte count instead of strlen; handle overflow and signs if needed; if the numeric pair can move, scan for the digit run with isdigit() rather than relying on a fixed offset. The OP () later confirmed success, so adding these checks hardens the solution for real-world serial input.

Recommended Answers

All 5 Replies

have a read about the atoi() function

Hello Freaky_Chris

Thanks for your answer, but atoi() doesn't work for me. I have chars like R1H81R1, and I need only the 81 in the middle, but not any other number in the char. As I understand, atoi would return me 1811 instead of the 81 that I need

Thank you

int x;
	sscanf(str,"%*c%*d%*c%d", &x);

well if you know the exact position of those chars you can easily extract them from the string you read them in... for example, the given the position and length of the integer, you could go with something like this:

#include <cstdio>

char str[ 256 ];
int pos, len, sol = 0;

int main( void )
{
    scanf( "%s", str );
    scanf( "%d%d", &pos, &len );
    
    for( int i = pos; i < pos + len; ++i ) {
         sol *= 10; sol += str[i] - '0';
    }
    
    printf( "%d\n", sol );
    
    scanf( "\n" );
    return 0;
}

thanks ivailosp and gregorynoob, that worked perfectly! :D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.