如何从字符串中提取整数?

8
我正在处理一项任务,作为其中的一部分,我需要从字符串中提取整数。
我试过使用`atoi()`函数,但它总是返回0,所以我转而使用`strtol()`函数,但它仍然返回0。
目标是从字符串中提取整数,并将它们作为参数传递给另一个函数。我正在使用一个函数来使用这些值来更新一些数据(`update_stats`)。
请记住我在C语言编程方面还相对新手,但这是我的尝试:
void get_number (char str[]) {
    char *end;
    int num;
    num = strtol(str, &end, 10);
    update_stats(num);
    num = strtol(end, &end, 10);
    update_stats(num);
}

这个问题的目的是从字符串"e5 d8"(例如)中提取出58

该字符串的格式始终相同。

我应该如何做到这一点?


1
这段代码没有明显的错误,因此问题无法重现。 - Lundin
1
你可以使用循环和 isdigit 函数来跳过所有非数字字符,然后再使用 strtol 函数。 - Bodo
1
atoistrtol都期望接收指向数字的第一个字符的指针——您的指针必须已经指向数字。当基数为10时,“e”和“d”都不是数字。要在字符串中找到数字,您应编写代码检查每个字符以确定它是否为数字。一旦找到数字,您可以将其(仅一个数字)或数字序列(多个数字)转换为数字,具体取决于您的需求。 - Eric Postpischil
@Lundin:这里有一个非常明显的错误;将指向字符串“e5 d8”第一个字符的指针传递给strtol函数并不是正确的找到“5”并将其转换为数字的方法。 - Eric Postpischil
@EricPostpischil确实,如果这是实际输入的话。没有调用代码很难确定。 - Lundin
3个回答

7

strtol函数并不会在字符串中寻找数字,它只会转换位于字符串开头的数字。(它会跳过空格,但不会跳过其他字符。)

如果您需要找到数字的起始位置,可以使用以下代码:

const char* nump = strpbrk(str, "0123456789");
if (nump == NULL) /* No number, handle error*/

(strpbrk手册)

如果您的数字可能是带符号的,那么您需要更加复杂的方法。一种方法是执行上述操作,如果前一个字符是-,则向后退一位。但要注意字符串的开头:

if ( nump != str && nump[-1] == '-') --nump;

如果在 strpbrk 参数中只输入 -,会导致像 non-numeric7 这样的输入产生错误的匹配。


1
如果格式一直是这样的,那么这也可以工作。
#include <stdio.h>

int main()
{
    char *str[] = {"a5 d8", "fe55 eec2", "a5 abc111"};
    int num1, num2;

    for (int i = 0; i < 3; i++) {
      sscanf(str[i], "%*[^0-9]%d%*[^0-9]%d", &num1, &num2);
      printf("num1: %d, num2: %d\n", num1, num2);
    }
    return 0;
}

输出

num1: 5, num2: 8                                                                                                                                                                   
num1: 55, num2: 2                                                                                                                                                                  
num1: 5, num2: 111

%[^0-9] 可以匹配任何非数字字符。通过添加 *,如 %*[^0-9] 表示从字符串中读取数据,但忽略它。


很好地使用了 sscanf。我真的很感激你的努力。然而,并没有明确指定格式是你所默认的方式。如果可以的话,请尝试添加更多的通用性。此外,如果用户在 I/O 和字符串转换为整数方面遇到困难,那么他/她很可能是新手。因此,提供文档链接或至少提供链接将非常有帮助,例如,在这种情况下,sscanf。不过回答得很好 :) - kesarling He-Him
1
好的,谢谢。但是请注意问题中写道:“字符串的格式始终相同。”,这意味着可以这样做。泛化是一件好事,但没有它也可以让解决方案像这样工作。在 Google 上搜索“sscanf”的第一个结果就是文档。我认为这里真正需要改进的是对格式的简要说明,我可以在这里添加。 - Eraklon
是的,没错。抱歉,我想我漏掉了最后一句话。不过答案很好哦 :) - kesarling He-Him

0

我建议你自己编写逻辑。我知道这就像“重复造轮子”,但在这种情况下,你将深入了解库函数的实际工作原理。

以下是我提出的一个函数:

bool getNumber(str,num_ptr)
char* str;
long* num_ptr;
{
    bool flag = false;
    int i = 0;
    *num_ptr = 0;
    char ch = ' ';
    while (ch != '\0') {
        ch = *(str + i);
        if (ch >= '0' && ch <= '9') {
            *num_ptr = (*num_ptr) * 10 + (long)(ch - 48);
             flag = true;
        }
        i++;
    }
    return flag;
}

不要忘记在末尾传递一个带有\0的字符串 :)

该函数扫描整个字符串并返回按顺序排列的数字组成的数字。 - kesarling He-Him
考虑到 c,您可以将布尔值转换为整数,并将 truefalse 分别转换为 10 - kesarling He-Him

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接