C++:获取字符数组中字符元素的索引

9
我需要获取数组中字符的数量。
const char myarray[5] = {'0', 'a', 'e', 'f', 'c'}; // Create array of char
int number=0; // Create variable
number = getposition(myarray, 'f'); // Now number equals to 3
number = getposition(myarray, 'z'); // -1, because array doesn't have this char

我的任务很容易,因为数组中没有重复字符(例如,它不能是这样的:{'a','1','f','a'})。我该怎么做?


你是指“字符的索引”吗? - xtofl
你可以返回一个位置数组。 - Aurelio De Rosa
是的。不是索引,而是一个索引:正如我所说,没有重复的字符。 - ghostmansd
memchr是你的好朋友 - 除非这是作业 - 如果是的话 - 你应该自己思考一下... - Nim
不,这是一种解码算法。我可以使用数百个if或use case来构建,但我认为可能会有更有效的决策。 - ghostmansd
6个回答

16
更多的C++:
#include <algorithm>

int getposition(const char *array, size_t size, char c)
{
     const char* end = array + size;
     const char* match = std::find(array, end, c);
     return (end == match)? -1 : (match-array);
}

更多的C++:
template <typename T, size_t N>
int getposition(const T (&array)[N], const T c)
{
     const T* match = std::find(array, array+N, c);
     return (array+N==match)? -1 : std::distance(array, match);
}

额外的C++11/C++11更新

#include <algorithm>
#include <iterator>

template <typename Range, typename T>
size_t index_of(Range const& range, T const& c) {
    using std::begin;
    using std::end;

    auto b = begin(range), e = end(range);
    auto match = std::find(b, e, c);

    return (e==match)? -1 : std::distance(b, match);
}

C++17的额外更新

在这里,原始问题直接得到了std::string_view的支持:

在Coliru上实时演示

#include <string_view>
using namespace std::string_view_literals;

int main() {
    return "hello"sv.find('e');
}

第一个选项才是C++中唯一正确的答案。如果这个问题是用C语言描述的,那么正确的回答是memchr(由另一个发帖者提到)。这个问题是一个经典的线性搜索问题,你不需要重新发明轮子(除非这是练习的目的)。 - James Kanze
1
这里的第一个肯定是错误的,因为它使用了 strlen 而不是 size 参数,并且我们不知道数组是否是字符串(示例中的数组不是),如果是,则不知道是否应该搜索 0 终止符。但除此之外,基本上是正确的。您可以使用 std::begin(array), std::end(array) 来获得“更 C++”版本,尽管那样它也不需要为捕获 N 广告模板推断技巧,因为它可以只采用单个模板参数 Range - Steve Jessop
@SteveJessop: 嘿嘿。你能看出我是从楼主那里复制的吗...这就是我抄袭而没有好好阅读它的下场 :( 已修复。关于基于范围的版本,我考虑添加它了(但我已经有2个选项了,结果速度在SO很重要)。 - sehe
在第二个代码块中,end未定义。然而,在第一个代码块中,它已经被定义了。我错过了什么吗? - James Little
1
@JamesLittle 哇,这些年怎么没人注意到呢。我趁机添加了 C++11、C++14 和 C++17 版本,它们更加详尽和优雅!干杯 - sehe
@sehe 太好了,我很高兴我没有疯掉。感谢您的更新! - James Little

8
#include <algorithm>

template <typename T, size_t size>
int getposition(T const (&array)[size], T const & c)
{
    T const * found = std::find(&array[0], &array[size], c);
    return found == &array[size] ? -1 : found - array;
}

非常好,但相当神秘 ;) - m0skit0
我真的很想点赞,如果只是将found - array替换为std::distance(array, found)就好了。 - xtofl
1
@xtofl:我真的看不出有什么意义-这个函数特别处理数组,而不是通用的迭代器范围。 - Mike Seymour
@MikeSeymour:我编辑了这篇帖子:“第二个参数缺少了类型T”。希望你没问题。 - Nawaz
@Nawaz:不是的;我已经回滚以删除重复的 T - Mike Seymour
显示剩余2条评论

5

你需要告诉getposition()方法在数组中搜索多少个元素,由于该数组在编译时初始化,因此可以使用sizeof指令:

int number = getposition(myarray, sizeof(myarray), 'f');

...

int getposition(const char *array, size_t size, char c)
{
    for (size_t i = 0; i < size; i++)
    {
        if (array[i] == c)
            return (int)i;
    }
    return -1;
}

在函数中使用多个返回语句并不能提高维护性和可读性。 - m0skit0
2
@m0skit0:添加额外的变量和break语句也无法解决问题。 - Mike Seymour
1
@m0skit0:为了遵循您的建议并避免早期返回,您需要添加一个“break”(或更复杂的终止条件)和一个变量来存储返回值。或者您有什么建议可以避免早期返回,并且在某种程度上比这更易读? - Mike Seymour
3
我同意单一返回的概念,但不适用于维护不需要考虑的简单函数,鉴于函数的规模。我认为@m0skit0并没有真正提供“证明”单一return最好的答案 - 他的回答比必要复杂得多,维护会是一个真正的问题。 - trojanfoe
@m0skit0:再加两个变量。还需要一些额外的代码来纠正你引入的那个差一错误。有时候,早期返回确实是最清晰的做法,即使在30年前它曾经短暂地不流行过。 - Mike Seymour
显示剩余9条评论

2
int getposition(const char* a, int arr_size, char to_find)
{
    int pos = -1;

    for(int i = 0; i < arr_size; ++i)
    {
        if(a[i] == to_find)
        {
            pos = i;
            break;
        }
    }

    return pos;
}

甚至不能编译...这不是函数。在发布回答之前,请确保您的答案正确 ;) - m0skit0
1
更新了一些可以编译和运行的内容。我的第一个答案实话说很糟糕。其他答案也比我的聪明多了 :-) - Firedragon
2
@m0skit0:你的回答也无法编译,你知道俗话说得好:“自己人做错了事,不要嘲笑别人同样的错误”。 - trojanfoe

1
如果这确实是一个纯解码练习 - 为什么不重新组织你的数组... 然后查找就是常数时间 - 例如..
int lt[128]; // ignoring negative values..

memset(lt, -1, 128); // initialize all to -1

// set the ones you want mappings for..
lt['0'] = 0;
lt['a'] = 1;
lt['e'] = 2;
lt['f'] = 3;
lt['c'] = 4;

所以现在你的查找函数是:

int indexOf(char v) { return lt[v]; }

在性能方面,你很难超越它...


-2

你需要同时将数组大小传递给函数。

int getposition(const char* array, size_t array_size, char value)
{
    int ret = -1;

    int i = 0;
    bool found = false;
    while (i < array_size && !found)
    {
        found = (array[i++] == value);
    }

    if (found)
    {
        ret = i - 1;
    }

    return ret;
}

看起来我们都过度思考了:第一次出现就可以了。 - xtofl
有趣的是,trojanfoe 没有从你那里得到任何负面评价。而我也不想添加额外的 return,这就是重点 ;) - m0skit0
1
@m0skit0:你的回答中有一些错误:输入数组应该是“const char *”。你不应该用“-1”初始化一个“unsigned”类型(“ret”),而且“boolean”不是一个有效的C++关键字。这个问题是关于数组大小的,而不是如何教条地编程。 - trojanfoe
真是对不起!正确并已修复。你可以按你想要的方式编程,我也可以按我想要的方式编程。可能有一天你会明白为什么多次返回值是不可取的。在那之前,我会给你点赞的评论 ;) - m0skit0
抱歉,但我的代码没有可维护性或易读性问题。的确,我写得太快了,说话也太多了,但我可以为自己辩解,因为我正在工作中,编写Java、Perl和SQL代码,容易混淆。但我不会为自己找借口。无论如何,问题已经得到了回答,我的回答被正确地投了反对票,所以我退出这个讨论。祝你们编程愉快 :) - m0skit0
显示剩余3条评论

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