ページ 11

文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月08日(土) 15:44
by あーてぃ
[1] 質問文
 [1.1] 自分が今行いたい事は何か
「猫でも分かるC言語プログラミング」という本の第8章練習問題にて、「関数を利用し、文字列の文字を反対に並べ替えるプログラムを作って下さい。」との問題が有り、プログラムを書いてみました。

 [1.2] どのように取り組んだか(プログラムコードがある場合記載)

コード:

#include<stdio.h>
#include<stdlib.h>

int reverse(char *str,int leng,char *rstr);

int main(void){

	char str[120],rstr[120];
	size_t leng;

	printf("文字を入力して下さい\n");
	gets(str);
	leng = strlen(str);

	reverse(&str[0],leng,&rstr[0]);

	printf("入力した文字は%sです。\n"
			"反対にすると%sです。\n"
			"文字の長さは%dです。",str,rstr,leng);

	return 0;
}

int reverse(char *str,int leng,char *rstr){
	int i;

	for(i=0;i<leng;i++){
		*(rstr+i) = *(str+leng-1-i);
	}
	*(rstr+leng) = '\0';
	return 0;
}


 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
 1・「あ」などの全角文字を入力すると、表示がおかしくなります。
【例1】(コマンドプロンプトの出力結果です。)
文字を入力して下さい

入力した文字はあです。
反対にするとbナす。文字の長さは2です。
1文字目の数字はFFFFFF82 2文字めの数字はFFFFFFA0


【例2】
文字を入力して下さい
あasd
入力した文字はあasdです。
反対にするとdsabナす。文字の長さは5です。
1文字目の数字はFFFFFF82 2文字めの数字はFFFFFFA0


2・ゆくゆくは、全角文字と半角文字を混ぜた文字列も逆に出来るように考えています。しかし、その方法がうまく思いつかず困っています。

 [1.4] 今何がわからないのか、知りたいのか
1・
1文字目の数字はFFFFFF82 2文字めの数字はFFFFFFA0
の部分におけるFという文字が何故連続しているのか。

2・全角文字と半角文字を混ぜた文字列も逆に出来るようにする方法。

[2] 環境  
 [2.1] OS : Windows7
 [2.2] コンパイラ名 : Visual Studioコマンドプロンプト

[3] その他
 ・どの程度C言語を理解しているか
学校でC言語について学んではいたものの、イマイチ身に付けることが出来なかったため、独学で勉強をしようと思いました。
入門書を3冊ほど読み、関数、ポインタ、構造体あたりをウロウロとしています。

Re: 文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月08日(土) 16:55
by みけCAT
あーてぃ さんが書きました:1文字目の数字はFFFFFF82 2文字めの数字はFFFFFFA0
の部分におけるFという文字が何故連続しているのか。
この表示をしていそうな部分が提示されたプログラムに見当たらず、string.hがインクルードされていないことから考えると、
これはstrlenという名前の自作関数で表示しているのでしょうか?
これを表示している部分のソースコードを提示していただけると答えやすくなります。
あーてぃ さんが書きました:全角文字と半角文字を混ぜた文字列も逆に出来るようにする方法。
全角文字はそれを表しているデータをまとめて移動する必要があります。
このプログラムでは入力のバッファと出力のバッファが独立しているので、
単純に1文字ずつ(1バイトずつではない)移動すればいいと思います。
Shift_JISのデータの範囲はhttp://www.tohoho-web.com/wwwkanji.htm
UTF-8のデータの範囲はhttp://ja.wikipedia.org/wiki/UTF-8
などに載っています。

Re: 文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月10日(月) 03:52
by あーてぃ
こんばんは、あーてぃです。

みけCATさんへ。
すみません、コピーペーストする際に下手に一部を消したのが不味かったようです。
少し改変もいたしましたので、全体ソースコードと合わせて、変えた部分を以下に記します。

【ソースコード】

コード:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int reverse(char *str,int leng,char *rstr);

int main(void){

	char str[120],rstr[120];
	size_t leng;

	printf("文字を入力して下さい\n");
	gets(str);
	leng = strlen(str);

	reverse(&str[0],leng,&rstr[0]);

	printf("入力した文字は%sです。\n"
			"反対にすると%sです。\n"
			"文字の長さは%dです。\n",str,rstr,leng);

	printf("1文字目の数字は%02X\n"
			"2文字めの数字は%02X",str[0],str[1]);

	return 0;
}

int reverse(char *str,int leng,char *rstr){
	int i;

	for(i=0;i<leng;i++){
		*(rstr+i) = *(str+leng-1-i);
	}
	*(rstr+leng) = '\0';
	return 0;
}
【変えた点】
includeに<string.h>を3行目に追加。
文字のASCII文字の番号を表示するprintf関数を22行目に追加。


【実行結果例】
…その1
文字を入力して下さい
あsd
入力した文字はあsdです。
反対にするとр唐bナす。
文字の長さは6です。
1文字目の数字はFFFFFF82
2文字めの数字はFFFFFFA0


…その2
文字を入力して下さい
asd
入力した文字はasdです。
反対にするとdsaです。
文字の長さは3です。
1文字目の数字は61
2文字めの数字は73


【知りたいこと】
-1
全角文字を入れると表示が「FFFFFF82」といったように、Fが連続するのはなぜか。
―2
みけCAT さんが書きました:全角文字はそれを表しているデータをまとめて移動する必要があります。
このプログラムでは入力のバッファと出力のバッファが独立しているので、
単純に1文字ずつ(1バイトずつではない)移動すればいいと思います。
ううむ……どうにも、今の自分の知識では、その方法を思いつくことが出来ません。
ヒントを教えて頂けませんか?

Re: 文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月10日(月) 05:24
by へにっくす
1.に関しては、charの範囲(-128〜127)だからとしか言えないですね。
8bitしかないcharを、32bitのint型に拡張しているだけですよ。「%02x」と指定してますが、xはunsigned intを前提としています。負の表現はできないと思ってください(とゆーかこれが負の表現なんだけど ^^;)。
-1〜-128→0xFF〜0x80となるはずですがこの置き換えをせずそのままintとして見るため、0xFFFFFFFF〜0xFFFFFF80となってしまうのです。
当然2桁を超えますから、02を指定しても無意味というわけです。
なのでcharでなくunsigned charにするといいかもしれません。うまくいかなかったらすみません・・・


2.ヒントというかそのものずばりかもしれないページ
http://www.kab-studio.biz/Programing/Pr ... n/207.html

Re: 文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月11日(火) 00:28
by かずま
コードを Shift-JIS に限定するなら、

コード:

#include <stdio.h>   // get
#include <string.h>  // strlen
 
void reverse(const char *str, int leng, char *rstr);
 
int is2byte(unsigned char c) { return (c ^ 0x20) - 0xa1u < 60u; }
 // i.e. { return (c>=0x81 && c<=0x9f) || (c>=0xe0 && c<=0xfc); ]

int main(void)
{
    char str[120], rstr[120];
    size_t leng;
 
    printf("文字を入力して下さい\n");
    gets(str);
    leng = strlen(str);
    reverse(str, leng, rstr);
    printf("入力した文字は「%s」です。\n"
           "反対にすると「%s」です。\n"
           "文字の長さは %d です。\n", str, rstr, leng);
    printf("1文字目の数字は %02X\n"
           "2文字めの数字は %02X\n",
           (unsigned char)str[0], (unsigned char)str[1]);
    return 0;
}
 
void reverse(const char *str, int leng, char *rstr)
{
    int i = 0, j = leng;
 
    rstr[j] = '\0';
    while (i < leng) {
        if (is2byte(str[i]))
            j -= 2;
            rstr[j] = str[i++];
            rstr[j+1] = str[i++];
        } else
            rstr[--j] = str[i++];
}
もっと汎用性のあるプログラムをご希望でしょうか?

Re: 文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月11日(火) 00:38
by かずま
かずま さんが書きました:

コード:

    while (i < leng) {
        if (is2byte(str[i]))
訂正です。

コード:

    while (i < leng)
        if (is2byte(str[i])) {

Re: 文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月13日(木) 16:33
by あーてぃ
こんにちは、あーてぃです。


みなさん、返信ありがとうございます。

へにっくすさん、ご回答有難うございます。
貼っていただいたサイトは、僕の知りたかったことに近い部分が書いてありました。
まだ読み進められていないので、もう少し読み進めて見ようと思います。

かずまさん、ソースコードの例を出していただき、ありがとうございます。
全角の際に行う関数処理と、インクリメントとデクリメントを利用することで綺麗になった関数の中身が勉強になりました。
しかし、自分の文字環境が関係してるのか、やはり全角と半角が混じった文字列は綺麗に逆になりませんでした。
かずま さんが書きました:コードを Shift-JIS に限定するなら、
文字コードに関して、まだ自分の知識の理解が追いついていないようです。
まずは少しばかり自分の力で調べてみて、改めて疑問がわきましたら、掲示板で質問させていただきたいと思います。

また質問する際はよろしくお願い致します。m(__)m

Re: 文字列の文字を反対に並べ替えるプログラムについて

Posted: 2014年3月13日(木) 16:35
by あーてぃ
連投失礼します。解決を押し忘れました(汗