开发者

How to iterate backwards in an array in C?

I am trying to input a string of characters, and then output them backwards like

Input: Hello Output: olleH

I have a working example, however I am getting every single letter except the last.

#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100

int main(void) {
i开发者_StackOverflownt my_stg2[MAX_SIZE];
int i = 0;
int j;
char my_stg[MAX_SIZE];

int input ;

input = getchar();

while (input != '\n'){//The new line is the stopping point.


    my_stg2[i] = input;
    ++i;
 input = getchar();


}
    for (j=0;i>=0;i--){



    my_stg[j]  = my_stg2[i];
    j++;
}

printf("%s\n" , my_stg);

}

I tried the above code, however I am getting weird output with large strings. Can someone fix the loop for me? http://imgur.com/PK97b.png


Ok. In order to solve cases like this you should really do what Kristopher Johnson says and go through it on paper to figure out how your variables will change during the execution of your program. Pen and paper are some of the most important tools a programmer has.

Just because I know it can be hard to do this if you don't know how to do it, let me talk you through it.

Assume the input "Hello\n". Before you start looping you will have the following values:

i = 0 & input = 'H'

You then go on to loop:

while (input != '\n') { my_stg2[i] = input; ++i; input = getchar(); }

for each iteration in your loop, your values will change to be:

i = 1 & input = 'e' & my_stg2[0] = 'H'
i = 2 & input = 'l' & my_stg2[1] = 'e'
i = 3 & input = 'l' & my_stg2[2] = 'l'
i = 4 & input = 'o' & my_stg2[3] = 'l'
i = 5 & input = '\n' & my_stg2[4] = 'o'

So. i is now 5.

You now go on to the second loop, and you do the following:

for (j = 0; j <= i; j++) { --i; my_stg[i] = my_stg2[j]; }

you start to loop, and after having decremented i you have the following value pairs:

j = 0 & i = 5 & my_stg[4] = my_stg2[0] = 'H'
j = 1 & i = 4 & my_stg[3] = my_stg2[1] = 'e'
j = 2 & i = 3 & my_stg[2] = my_stg2[2] = 'l'

...and at the third step the loop stops. The output you get is "leH".

Now, why did the loop stop? Look over your conditions, and you'll find your answer.


Tweak your for loop as below

for (j=0; j < i; j++)
{
    my_stg[i - (j + 1)]  = my_stg2[j];
}

my_stg[i] = 0;


This is what you have

// The following line is pseudo-code.
// The '\0' is required in C to mark end of a character string.
orig := 'H', 'e', 'l', 'l', 'o', '\0'

with number of characters n = 6 (don't forget the \0).

Following is what you want to achieve

reverse := 'o', 'l', 'l', 'e', 'H', '\0'

So, this is what we have to do:

A. put a \0 in reverse[ n - 1 ]

B. We would read orig forward starting at index i = 0, and write to reverse backward starting at index j = n - 1. For that, we use two index variables:

  i, for indexing orig, starting at 0 and incrementing up to n - 1

  j, for indexing reverse, starting at n - 1 and decrementing down to 0

C. copy from orig[ i ] to reverse[ j ]

for( i = 0, j = n - 1; (i <= n - 1) && (j >= 0); ++i, --j ) {
   reverse[ j ] = orig[ i ];
}


There are 2 mistakes with your program.

First, realize that the value of "i" in your first loop is always set to "the index we will next write into".

i = 0; input = getchar();
while (input != '\n'){
    my_stg2[i] = input;
    ++i;
    input = getchar();
}

Exiting that loop after writing "Hello!", you would have

my_stg2[] = {'H', 'e', 'l', 'l', 'o', '!'}, i=6

When you start reading the values out of my_stg2 you should therefore start reading from (i-1) instead of from i.

The second problem is that after copying the contents of my_stg2 to my_stg you need to do:

my_stg2[j] = 0;

This is because strings in C use a trailing null to determine the end of the string. The reason you get garbage characters following your string in the picture you attached is because the printf() code will keep printing each successive byte in memory until it reaches a 0, and you never placed a 0 at the end of the my_stg string explicitly.

Alternately you could initialize the entire contents of my_stg2 to 0 at the start of your program with

memset(my_stg2, 0x00, sizeof(my_stg2));

This is an important lesson with C - when you declare a variable you need to initialize it or it will on some platforms be filled with whatever was previously stored in the memory location.


You have several issues in your code:

  1. int my_stg2[MAX_SIZE]; is an array of random ints when declared. These are of sizeof(int) on your platform -- probably 32 or 64 bits;

  2. char my_stg[MAX_SIZE]; is a array of random characters when declared. These are of sizeof(char) on your platform -- probably 8 bits;

  3. You are interchanging ints and characters with the assignment of my_stg[j] = my_stg2[i]; without a cast.

  4. You are not checking for a buffer overrun in while loop. If someone typed more than MAX_SIZE characters before a \n, you will overrun the buffer you allocated;

  5. You are not null terminating the string. If you are using getchar() that is a single character. You need to put a NUL after that or you will have a runaway string with the printf()

  6. In your while loop, you need to check for EOF

  7. It is counterintuitive, but getchar() is its own little loop like construct. It will not enter the while loop until an EOF or CR. It will then dump all the characters. You should not, then, test for CR against the getchar().

  8. Your second loop is off by one; you are copying the value after the last character.

This code works as you expects I believe:

#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100

int main(void) {
    char my_stg[MAX_SIZE], my_stg2[MAX_SIZE];
    int i,j,input = 0;

    while ((input=getchar())!=EOF) {
        if(input=='\n' || i>=MAX_SIZE-1) break;
        my_stg2[i++] = (char)input;
        my_stg2[i+1] = (char)0l;
    }

    printf("my_stg2= %s\ni=%i\n",my_stg2,i);

    for (j=0;i>0;i--,j++){
       my_stg[j]  = my_stg2[i-1];
       my_stg[j+1]=(char)0l;
       printf("i=%i %s\n",i,my_stg);
    }
    printf("%s\n" , my_stg);
    return EXIT_SUCCESS;
}

Because it get a bit tedious to think about strings as having a NUL termination, most people use the standard C library for strings.

You may also want to ponder doing this loop more efficiently. Reversing a string in place using 1/2 the memory and 1/2 the steps with a recursive function like this:

void strrev ( char *buff, int start, int end )
{
    char tmp ;
    static int i=0;

    if ( start >= end ) {i=0; return;}

    printf("%i strrev=%s\n",++i,buff);

    tmp = *(buff + start);
    *(buff + start) = *(buff + end);
    *(buff + end) = tmp ;

    strrev (buff, ++start, --end );
}

If you look at the output, you can see it is 1/2 the steps and without copying to another buffer:

Hello World!!!
my_stg2= Hello World!!!
i=14
i=14 !
i=13 !!
i=12 !!!
i=11 !!!d
i=10 !!!dl
i=9 !!!dlr
i=8 !!!dlro
i=7 !!!dlroW
i=6 !!!dlroW 
i=5 !!!dlroW o
i=4 !!!dlroW ol
i=3 !!!dlroW oll
i=2 !!!dlroW olle
i=1 !!!dlroW olleH
!!!dlroW olleH
Recursive:
1 strrev=!!!dlroW olleH
2 strrev=H!!dlroW olle!
3 strrev=He!dlroW oll!!
4 strrev=HeldlroW ol!!!
5 strrev=HelllroW od!!!
6 strrev=HelloroW ld!!!
7 strrev=Hello oWrld!!!
reverse the reverse: Hello World!!!


Have a look at a pointer backward-solution for your array question:

const char *loop = my_stg2 + strlen(my_stg2);
...
do {
  my_stg[loop-my_stg2] = *loop;
} while( my_stg2 != loop-- );
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜