简体   繁体   English

在没有两个循环的情况下反转字符串?

[英]Reversing a string without two loops?

I came up with the following basic item to reverse a string in C: 我想出了以下基本项来反转C中的字符串:

void reverse(char in[], char out[]) {

    int string_length = 0;

    for(int i=0; in[i] != '\0'; i++) {
        string_length += 1;
    }

    for(int i=0; i < string_length ; i++) {
        out[string_length-i] = in[i];
    }
    out[string_length+1] = '\0';
}

Is there a way to do this in one for loop or is it necessary to first use a for length to get the string length, and then do a second one to reverse it? 有没有办法在一个for循环中执行此操作,或者是否有必要首先使用for长度来获取字符串长度,然后再执行第二个来反转它? Are there other approaches to doing a reverse , or is this the basic one? 是否有其他方法可以进行reverse ,或者这是基本方法吗?

Assuming you can't use functions to get the string length and you want to preserve the second loop I'm afraid this is the shortest way. 假设您不能使用函数来获取字符串长度, 并且您希望保留第二个循环,我担心这是最短的方式。

Just as a side-note though: this code is not very safe as at for(int i=0; in[i] != '\\0'; i++) you are not considering cases where the argument passed to parameter in is not a valid C string where there isn't a single \\0 in all elements of the array pointed by in and this code will end up manifesting a buffer over-read at the first for loop when it will read beyond in boundaries and a buffer overflow in the second for loop where you can write beyond the boundaries of out . 正如一个侧面说明,虽然:此代码是不是在非常安全for(int i=0; in[i] != '\\0'; i++)你是不是考虑在参数传递到参数的情况下in不那里没有一个单一的一个有效的C字符串 \\0在阵列的所有元素指出通过in和该代码将最终表现缓冲在第一过读for loop时它会超越读取in边界和缓冲区溢出在第二个for loop ,你可以写出超出out的界限。 In functions like this you should ask the caller for the length of both arrays in and out and use that as a max index when accessing them both. 在这样的函数中,你应该向调用者询问两个数组的inout长度,并在访问它们时将其用作最大索引

As pointed by Rishikesh Raje in comments: you should also change the exit condition in the second for loop from i <= string_length to i < string_length as it will generate another buffer over-read when i == string_length as it will access out by a negative index. 正如在评论中指出由Rishikesh的Raje:你也应该从改变第二个for循环退出条件 i <= string_lengthi < string_length ,因为它会产生过度读取另一个缓冲器时i == string_length因为它会访问out由负面指数。

void reverse(char *in, char *out) {

    static int index;
    index = 0;

    if (in == NULL || in[0] == '\0')
    {
        out[0] = '\0';
        return;
    }
    else
    {
        reverse(in + 1, out);
        out[index + 1] = '\0';
        out[index++] = in[0];
    }
}

With no loops. 没有循环。

This code is surely not efficient and robust and also won't work for multithreaded programs. 这段代码肯定不是高效和健壮的,也不适用于多线程程序。 Also the OP just asked for an alternative method and the stress was on methods with lesser loops. OP也只是要求一种替代方法,并且压力在于具有较小环路的方法。

Are there other approaches to doing a reverse, or is this the basic one 是否有其他方法可以做反向,或者这是基本方法

Also, there was no real need of using static int . 此外,没有真正需要使用static int This would cause it not to work with multithreaded programs. 这将导致它无法与多线程程序一起使用。 To get it working correct in those cases: 为了使它在这些情况下正常工作:

int reverse(char *in, char *out) {

    int index;

    if (in == NULL || in[0] == '\0')
    {
        out[0] = '\0';
        return 0;
    }
    else
    {
        index = reverse(in + 1, out);
        out[index + 1] = '\0';
        out[index++] = in[0];
        return index;
    }
}

You can always tweak two loops into one, more confusing version, by using some kind of condition to determine which phase in the algorithm you are in. Below code is untested, so most likely contains bugs, but you should get the idea... 您可以随时通过使用某种条件来确定您所在算法中的哪个阶段,将两个循环调整为一个更令人困惑的版本。下面的代码未经测试,因此很可能包含错误,但您应该明白...

void reverse(const char *in, char *out) {

    if (*in == '\0') {
        // handle special case
        *out = *in;
        return;
    }

    char *out_begin = out;
    char *out_end;
    do {
        if (out == out_begin) {
            // we are still looking for where to start copying from
            if (*in != '\0') {
                // end of input not reached, just go forward
                ++in;
                ++out_end;
                continue;
            }
            // else reached end of input, put terminating NUL to out
            *out_end = '\0';
        }
        // if below line seems confusing, write it out as 3 separate statements.
        *(out++) = *(--in);
    } while (out != out_end); // end loop when out reaches out_end (which has NUL already)
}

However, this is exactly as many loop iterations so it is not any faster, and it is much less clear code, so don't do this in real code... 然而,这与循环迭代完全一样,因此它不是更快,而且代码更不清晰,所以不要在实际代码中这样做...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM