0

そのため、コマンド ラインから文字列を取り込み、その文字列をトラバースし、リンク リストを使用して反転する C プログラムを作成しようとしています。現在は機能していません。その理由はわかりません。私は今まで C++ でしかプログラミングしたことがないので、C の小さな違いに本当に頭を悩ませています。誰かが私のプログラムのエラーを見つけるのを手伝ってくれますか?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct st_CharNode 
{
char theChar;
struct st_CharNode *next;
} CharNode;


void reverseIt( char *stringbuffer );


int main( int argc, char *argv[] )
{
char *stringBuffer;

//  Check number of user supplied arguments.  
if( argc != 2 )
{
    fprintf( stderr, "usage: %s string.  This reverses the string "
             "given on the command line\n" );
    exit( -1 );
}

// Copy the argument so we can make changes to it
stringBuffer = malloc( strlen(argv[1]) );
strcpy( argv[1], stringBuffer );

// Reverse the string
reverseIt( stringBuffer );

// Print the reversed string
printf( "the reversed string is '%s'\n", *stringBuffer );

return 0;
}


// Build a linked list backwards, then traverse it.

void reverseIt( char *stringbuffer )
{
CharNode *head, *node;
char *scan, *stop;

// initialize local vars
head = node = NULL;

// find the start and end of the string so we can walk it
scan = stringbuffer;
stop = stringbuffer + strlen(stringbuffer) + 1;

// walk the string
while (scan < stop)
{
    if (head == NULL)
    {
        head = malloc( sizeof(CharNode*) );
        head->theChar = *scan;
        head->next = NULL;
    }
    else
    {
        node = malloc( sizeof(CharNode*) );
        node->theChar = *scan;
        node->next = head;
        head = node;
    }
    scan++;
}

// Re-point to the buffer so we can drop the characters
scan = stringbuffer;

//  Traverse the nodes and add them to the string
while( head != NULL )
{
    *scan = head->theChar;
    free( head );
    node = head->next;
    head = node;
    scan++;
}

// Release head
free( head );   
}

I ./a.out を実行し、コマンド ラインで "Hello" のような文字列を入力したときの現在の出力は、"逆文字列は '(null)'" です。

4

2 に答える 2

2

問題点をいくつか挙げてみると…

過少割り当て

C文字列に必要な終了ヌル文字を考慮していません。

これ:

stringBuffer = malloc( strlen(argv[1]) );

これでなければなりません:

stringBuffer = malloc( strlen(argv[1]) + 1);

間違ったコピー方向

割り当ての直後に、新しいバッファから初期化されていないデータをコピーしargv[1]、nulchar が検出されるまで上からブラストします。さらに未定義の動作。

これ:

strcpy( argv[1], stringBuffer );

これでなければなりません:

strcpy( stringBuffer, argv[1] );

Printf に渡された不適切な逆参照

"%s"フォーマット指定子は、一致する可変引数パラメーターとして渡されるヌル文字で終了する文字列のアドレスを必要とします。つまり、コンパイラによって*stringBufferに昇格された文字値であり、アドレスとして使用されます。intさらに悪いことに、これは可変引数関数であるため、これは完全にコード化できますが、実行すると明らかに未定義の動作になります。優れたコード静的分析コンパイラーは、これをキャッチします。

これ:

printf( "the reversed string is '%s'\n", *stringBuffer );

これでなければなりません:

printf( "the reversed string is '%s'\n", stringBuffer );

そして、そのすべては、実際の反転関数に入ることさえありません。少なくともこれらを修正してください。リンクされたリストを使用して C 文字列を逆にする必要はありません (そして、実際には夢中になるでしょう)。2 つのポインターと 1 つのループ (または 1 つのポインターとインデックス) で実行できるため、その関数を分析することは逆効果に思えます。文字列を逆にすることは、文字通り次のように簡単です (そしてその場で):

void reverse_str(char *str)
{
    if (!str || !*str || !*(str+1))
        return;

    char *rhs = str + strlen(str) - 1;
    while (str < rhs)
    {
        char tmp = *str;
        *str++ = *rhs;
        *rhs-- = tmp;
    }
}
于 2013-10-24T02:51:05.397 に答える
2

最大の間違いはラインにあります

strcpy( argv[1], stringBuffer );

構文は次のとおりです。

strcpy( char* destination, char* source );

あなたは明らかに2つが逆になっています。

また、ヌル文字に到達する前に必ず停止する必要があります。これを行うには、stop変数を現在実行している値よりも 1 小さい値に設定します。

stop = stringbuffer + strlen(stringbuffer) ;

printf文字列を出力するときは、関数に正しいパラメーター (文字列へのポインター)を与える必要があります。

printf( "the reversed string is '%s'\n", stringBuffer );

最後に-@WhozCraigのおかげで-終端の「\ 0」を考慮して、バッファにより多くのメモリを割り当てる必要があります。

stringBuffer = malloc( strlen(argv[1])) + 1 );

すべてをまとめると、次のコードが機能します (途中でいくつかのデバッグ printf ステートメントが含まれています。何が起こっているのかを理解しようとしている間は、常に良い考えです。

#include <stdlib.h>
#include <string.h>
typedef struct st_CharNode
{
char theChar; 
struct st_CharNode *next;
} CharNode;


void reverseIt( char *stringbuffer );


int main( int argc, char *argv[] )
{
char *stringBuffer;

//  Check number of user supplied arguments.
if( argc != 2 )
{
    fprintf( stderr, "usage: %s string.  This reverses the string "
             "given on the command line\n" );
    exit( -1 );
}

// Copy the argument so we can make changes to it
stringBuffer = malloc( strlen(argv[1]) + 1 );
strcpy( stringBuffer, argv[1]);

// Reverse the string
reverseIt( stringBuffer );

// Print the reversed string
printf( "the reversed string is '%s'\n", stringBuffer );

return 0;
}   

// Build a linked list backwards, then traverse it.

void reverseIt( char *stringbuffer )
{
CharNode *head, *node;
char *scan, *stop;

// initialize local vars
head = node = NULL;
printf("reversing '%s'\n", stringbuffer);

// find the start and end of the string so we can walk it
scan = stringbuffer;
stop = stringbuffer + strlen(stringbuffer) ;

// walk the string
while (scan < stop)
{
    printf("character: %c\n", *scan);
    if (head == NULL)
    {
        head = malloc( sizeof(CharNode*) );
        head->theChar = *scan;
        head->next = NULL;
    }
    else
    {
        node = malloc( sizeof(CharNode*) );
        node->theChar = *scan;
        node->next = head;
        head = node;
    }
    scan++;
}

// Re-point to the buffer so we can drop the characters
scan = stringbuffer;
printf("==== now reversing:====\n");
//  Traverse the nodes and add them to the string
while( head != NULL )
{
    *scan = head->theChar;
    printf("character: %c\n", *scan);
    free( head );
    node = head->next;
    head = node;
    scan++;
}
*stop = 0; // add the terminating nul
// Release head
free( head );
}
于 2013-10-24T02:55:09.723 に答える