【问题标题】:Converting string of numbers seperated by spaces into int array将由空格分隔的数字字符串转换为int数组
【发布时间】:2018-02-16 08:11:15
【问题描述】:

我正在尝试构建一个递归函数,该函数获取一个字符串(char 数组),该字符串应包含由空格或制表符分隔的数字,以及应插入的数字数量,并将每个数字插入一个 int 数组。 我不能对这个函数使用任何循环,只能递归。 两个数字之间的空格和制表符的数量是未知的。 (虽然 char 数组是 1000 个字符的缓冲区) 我正在使用 gets_s 作为输入字符串。 如果字符串中有错误的字符或插入的数字数量不正确,该函数将打印错误并重新启动(再次没有任何循环)。 允许使用 +/- 符号和前导零 (001)。

到目前为止,我有一个函数,它获取一个包含有效数字的 char 数组并将其值返回为 int(例如 {'-','1','5','\0'} 将返回 -15)。

将字符串转换为 int 数组以便在我的程序中使用该数组的最佳方法是什么?

谢谢

【问题讨论】:

  • "什么是最好的方法..." 使用循环:)
  • 这种“不使用最合适的工具来解决”的问题对你来说应该是一个危险信号;你的资源,无论是什么,都在教你以不恰当的方式解决问题。为什么,在现实世界中,没有人在这里使用 C 语言中的循环?或者,如果作者想教授函数式编程,他们为什么要使用非函数式语言,比如 C? 买一本更好的书!

标签: c


【解决方案1】:

在我写的cmets中:

这种“不使用最合适的工具来解决”的问题对你来说应该是一个危险信号;你的资源,无论是什么,都在教你以不恰当的方式解决问题。为什么,在现实世界中,没有人在这里使用 C 语言中的循环?或者,如果作者想教授函数式编程,他们为什么要使用非函数式语言,比如 C? 买一本更好的书!

尽管如此,我发现自己在这里提供了一个答案......

首先,从技术上讲,它们都是循环!我收集当你声明你不能使用任何循环时,你实际上指的是过程循环(即从gotowhile、@构建的循环987654323@ 或 for),而不是 功能循环(由递归函数应用程序构建)。从技术上讲,它们都是循环,并且由于 C 是一种过程语言您应该使用过程循环。不过……

有一个模式!只需通过观察和重现一个模式,程序循环就可以转换为功能循环。也就是说,每个程序循环都有一个等效的功能循环,它们最终看起来都非常相似。寻找下面的模式。

这是一个包含基本过程循环的函数

void procedural_loop_on_str(char const *source, size_t source_position, int *dest, size_t dest_position) {
    while (source[source_position] != '\0') {
        source_position++;
    }
}

...这里是一个功能循环:

void functional_loop_on_str(char const *source, size_t source_position, int *dest, size_t dest_position) {
    if (source[source_position] != '\0') {
        source_position++;
        functional_loop_on_str(source, source_position, dest, dest_position);
    }
}

这两段代码看起来很相似,不是吗?基于此观察,任何程序循环都可以简单地转换为功能等价物;您要做的就是添加填充循环的额外代码。作为练习,请考虑隔离此代码中相同的部分。它们通常在两段代码中位于同一个位置;他们不难找到!事实上,这些差异并列如下:

    while ...                                  if ...
                                                   functional_loop_on_str...

当需要回溯时,唯一的困难就出现了,这与这个问题无关。因此,您应该能够编写过程版本并将其轻松转换为功能版本。请允许我开始:

void procedural_loop_on_str(char const *source, size_t source_position, int *dest, size_t dest_position) {
    while (source[source_position] != '\0') {
        int value, nbytes, success = sscanf(source + source_position, "%d%n", &value, &nbytes);
        if (!success) { nbytes = 1; }
        else { /* XXX: You do this part!
                *      You need to do something with value, dest and dest_position */
        }
        source_position += nbytes;
    }
}

...这里通过复制模式将其转换为我们的功能版本

void functional_loop_on_str(char const *source, size_t source_position, int *dest, size_t dest_position) {
    if (source[source_position] != '\0') {
        int value, nbytes, success = sscanf(source + source_position, "%d%n", &value, &nbytes);
        if (!success) { nbytes = 1; }
        else { /* XXX: You do this part!
                *      You need to do something with value, dest and dest_position */
        }
        source_position += nbytes;
        functional_loop_on_str(source, source_position, dest, dest_position)
    }
}

请注意这两个示例之间的实际变化很小;大部分模式仍然存在!还记得上面的练习吗?好吧,你可以在这里做同样的事情,发现从程序性转换为功能性时,在同一个地方进行了相同的更改。

我认为,如果您阅读了一本(更好的)关于函数式编程的书和一本(更好的)关于 C 编程的书,或者甚至自己创建了这些基本示例来观察该模式,那么我认为这种模式对您来说是显而易见的。尽管如此,我坚持我的信念:

  1. 您不应该在 C 或任何过程语言中使用函数循环,尤其是不是 C;如果 C 是为日常功能循环而设计的,那么标准中就会有优化保证。如果您的指南另有说明,请考虑选择新指南,例如由 C Kernighan & Richie 的创始人所写的带有巨大蓝色“C”的书(选择第二版)。我会让你找到那个。
  2. 您不应该使用过程语言来研究功能元素。这是不言而喻的。考虑方案;有一本关于 Scheme 的非常好的“向导书”!

不管怎样,看来你需要一本更好的书

【讨论】:

  • 赞成 但我认为仅仅因为它提供了愚蠢的递归示例就说“买一本更好的书”有点苛刻。如果您要引入递归,那么第一个示例总是很愚蠢,因为有意义的递归候选者的第一步太复杂了。
  • @Persixty “对于之前没有在合适的环境中充分研究过递归的任何人来说,递归的有意义的候选者都是太复杂的第一步”。请研究 Haskell,其中没有过程循环,因此您必须对 每个 候选者使用递归,无论多么不复杂,并且然后过来和我谈谈。
  • @Persixty 递归不是一个复杂的话题。因此,我坚持我的信念,即 OP 要么需要一本关于递归的更好的书,要么需要一本关于 C 的更好的书……可能两者兼而有之,但很可能是后者。
  • 而且我认为您低估了 1 个代表的 OP 找到它的难度。但是无所谓。仍然赞成。
  • @Persixty 我们都曾经是“1 rep”,我认为根据这样的数字来判断一个人的智力是不尊重的。如果你想被那样看待,那就这样吧。我宁愿假设即使是“1 rep”的用户也能够研究以找到值得学习的合理书籍。
【解决方案2】:

传递一个指向整数数组末尾的指针作为函数的参数以及指向字符串中当前字符的指针。如果不是空白,则将数字添加到 int 数组并递增 int 指针。适当地增加 char 指针 regaurdless 和递归。我假设您可以处理将字符串转换为整数,如果没有,有很多帖子可以帮助解决这个问题。

【讨论】:

    【解决方案3】:

    sscanf 听起来像是您需要的工具。这是我会使用的那个。您可以递归地将您的字符串读入您的 int 数组。我还将创建一个具有 501 个位置的 int 数组,因为这是您可以获得的最大数量的 int(如果每个 int 只是一个数字并且它们之间只有一个空格)。

    您也可以使用atoi

    【讨论】:

      猜你喜欢
      • 2015-06-02
      • 1970-01-01
      • 2021-01-22
      • 1970-01-01
      • 2013-11-02
      • 2018-07-21
      • 1970-01-01
      • 2019-08-23
      相关资源
      最近更新 更多