ページ 11

文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 20:09
by かごめ
ビット演算子を使って顔文字を以下のように出力させたいのですか、このコードで出力させると何も出ず、エラーが出ていまい終わるだけです。
どうすれば一文字ずつ消えるように出力させるでしょうか?
<結果>
Σ(・ω・ノ)ノ!
(・ω・ノ)ノ!
・ω・ノ)ノ!
ω・ノ)ノ!
・ノ)ノ!
ノ)ノ!
)ノ!
ノ!

コード:

#include<stdio.h>

int main(void){
	int i, j;

	char kaomozi[] = "Σ(・ω・ノ)ノ!";
	
	for (i = 0; i < 9; i++){
		printf("%s", kaomozi[]<<1);
		printf("\n");
	}

	return 0;
}

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 20:23
by みけCAT
一文字ずつ消すように出力の開始位置をずらしていくといいでしょう。

コード:

#include<stdio.h>

int main(void){
	int i, j;

	char kaomozi[] = "Σ(・ω・ノ)ノ!";
	
	for (i = 0; kaomozi[i]; i++){
		printf("%s", kaomozi + i);
		printf("\n");
#if 1
		/* Shift-JISの場合 */
		j = (unsigned char)kaomozi[i];
		if (((0x81 <= j && j <= 0x9f) || (0xe0 <= j && j <= 0xef))){
			j = (unsigned char)kaomozi[i + 1];
			if (0x40 <= j && j != 0x7f && j <= 0xfc) i++;
		}
#else
		/* UTF-8の場合 (不正チェックは省略) */
		j = (unsigned char)kaomozi[i];
		if (0xfe <= j) ; /* 不正なので進めない */
		else if (0xfc <= j) i += 5;
		else if (0xf8 <= j) i += 4;
		else if (0xf0 <= j) i += 3;
		else if (0xe0 <= j) i += 2;
		else if (0xc0 <= j) i++;
#endif
	}

	return 0;
}
…あっ、これだとビット演算子を使っていませんね。どこか適当にねじ込んでください。

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 21:05
by かごめ
どこに入れればいいのかわからいないので質問しているのですが・・・

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 21:27
by box
そもそも、今回の問題をビット演算子で解決しようとするもくろみそのものが適切ではないのではないか、という気がします。
そんなことはないかな?

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 21:41
by かごめ
そういう課題なんで必要です。

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 21:52
by かずま
かごめ さんが書きました:そういう課題なんで必要です。
文字列はマルチバイトです。バイト列です。ビット演算子は不要です。
課題を一字一句変えずに書いてください。

とりあえず、プログラムを作ってみました。
VC++ では、このままいけると思います。
cygwin だと、set LANG=ja_JP.cp932 を実行した後だと大丈夫だと思います。
Linux では、環境変数 LANG=ja_JP.UTF-8 だと思うので、OK でしょう。
コンパイル時の警告は無視してください。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
 
int main(void)
{
    int i, n;
    wchar_t k[16];
    char *p = (char *)k;
    char kaomozi[] = "Σ(・ω・ノ)ノ!";
    setlocale(LC_ALL, "");
    n = mbstowcs(k, kaomozi, 16);
    for (i = 0; i < n; i++)
        printf("%ls\n", p + (i << (sizeof(wchar_t)>>1)));
    return 0;
}
理解できない場合、どこが分からないのかを質問してください。
それと、あなたの環境(OS やコンパイラ)が何かを書いてください。

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 22:34
by みけCAT
かごめ さんが書きました:どこに入れればいいのかわからいないので質問しているのですが・・・
例えば、整数の足し算をビット演算子を用いて行うことができます。

コード:

#include<stdio.h>

/* 全加算器をシミュレートする */
unsigned int add(unsigned int a, unsigned int b) {
	unsigned int pos = 1;
	unsigned int carry = 0;
	unsigned int answer = 0;
	while (pos) {
		unsigned int abit = a & pos;
		unsigned int bbit = b & pos;
		unsigned int digit = abit ^ bbit ^ carry;
		unsigned int next_carry = (abit & bbit) | (bbit & carry) | (carry & abit);

		answer |= digit;
		carry = next_carry << 1;
		pos <<= 1;
	}
	return answer;
}

int main(void){
	unsigned int i, j;

	char kaomozi[] = "Σ(・ω・ノ)ノ!";
	
	for (i = 0; kaomozi[i]; i = add(i, 1)){
		printf("%s", kaomozi + i); /* ここの加算はポインタ演算なので置き換えられない */
		printf("\n");
#if 1
		/* Shift-JISの場合 */
		j = (unsigned char)kaomozi[i];
		if (((0x81 <= j && j <= 0x9f) || (0xe0 <= j && j <= 0xef))){
			j = (unsigned char)kaomozi[add(i, 1)];
			if (0x40 <= j && j != 0x7f && j <= 0xfc) i = add(i, 1);
		}
#else
		/* UTF-8の場合 (不正チェックは省略) */
		j = (unsigned char)kaomozi[i];
		if (0xfe <= j) ; /* 不正なので進めない */
		else if (0xfc <= j) i = add(i, 5);
		else if (0xf8 <= j) i = add(i, 4);
		else if (0xf0 <= j) i = add(i, 3);
		else if (0xe0 <= j) i = add(i, 2);
		else if (0xc0 <= j) i = add(i, 1);
#endif
	}

	return 0;
}

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月03日(日) 22:48
by みけCAT
C++を使ってよければ、演算子をオーバーロードすればいいでしょう。

コード:

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

class moziretu {
	char* data;

public:
	moziretu(const char* str) {
		data = new char[strlen(str) + 1];
		strcpy(data, str);
	}
	~moziretu() {
		delete[] data;
	}
	// コピーコンストラクタ (The Rule of Three)
	moziretu(const moziretu& m) {
		data = new char[strlen(m.data) + 1];
		strcpy(data, m.data);
	}
	// 代入演算子 (The Rule of Three)
	moziretu& operator=(const moziretu& m) {
		delete[] data;
		data = new char[strlen(m.data) + 1];
		strcpy(data, m.data);
		return *this;
	}

	const char* operator<<(int index) const {
		char* pos = data;
		int c;
		for (; index-- && *pos; pos++) {
#if 1
			// Shift-JISの場合
			c = (unsigned char)*pos;
			if (((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))){
				c = (unsigned char)pos[1];
				if (0x40 <= c && c != 0x7f && c <= 0xfc) pos++;
			}
#else
			// UTF-8の場合 (不正チェックは省略)
			c = (unsigned char)*pos;
			if (0xfe <= c) ; // 不正なので進めない
			else if (0xfc <= c) pos += 5;
			else if (0xf8 <= c) pos += 4;
			else if (0xf0 <= c) pos += 3;
			else if (0xe0 <= c) pos += 2;
			else if (0xc0 <= c) pos++;
#endif
		}
		return pos;
	}
};

int main(void){
	int i;

	moziretu kaomozi = "Σ(・ω・ノ)ノ!";

	for (i = 0; i < 9; i++){
		printf("%s", kaomozi<<i);
		printf("\n");
	}

	return 0;
}
もしくは、<<1を使うなら

コード:

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

class moziretu {
	char* data;
	char* pos;

public:
	moziretu(const char* str) {
		data = new char[strlen(str) + 1];
		strcpy(data, str);
		pos = data;
	}
	~moziretu() {
		delete[] data;
	}
	// コピーコンストラクタ (The Rule of Three)
	moziretu(const moziretu& m) {
		data = new char[strlen(m.data) + 1];
		strcpy(data, m.data);
		pos = data;
	}
	// 代入演算子 (The Rule of Three)
	moziretu& operator=(const moziretu& m) {
		delete[] data;
		data = new char[strlen(m.data) + 1];
		strcpy(data, m.data);
		pos = data;
		return *this;
	}

	const char* operator<<(int index) {
		int c;
		char* ret = pos; // 演算前の値を返すようにする
		for (; index-- && *pos; pos++) {
#if 1
			// Shift-JISの場合
			c = (unsigned char)*pos;
			if (((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))){
				c = (unsigned char)pos[1];
				if (0x40 <= c && c != 0x7f && c <= 0xfc) pos++;
			}
#else
			// UTF-8の場合 (不正チェックは省略)
			c = (unsigned char)*pos;
			if (0xfe <= c) ; // 不正なので進めない
			else if (0xfc <= c) pos += 5;
			else if (0xf8 <= c) pos += 4;
			else if (0xf0 <= c) pos += 3;
			else if (0xe0 <= c) pos += 2;
			else if (0xc0 <= c) pos++;
#endif
		}
		return ret;
	}
};

int main(void){
	int i;

	moziretu kaomozi = "Σ(・ω・ノ)ノ!";

	for (i = 0; i < 9; i++){
		printf("%s", kaomozi<<1);
		printf("\n");
	}

	return 0;
}

Re: 文字列とビット演算子について教えてください。

Posted: 2016年7月04日(月) 09:56
by かずま
かごめ さんが書きました:どこに入れればいいのかわからいないので質問しているのですが・・・
j = (unsigned char)kaomoz; を j = kaomozi & 0xff; とすれば、
ビット演算子 & を使ったことになります。

int le(int a, int b) { return ~(b-a >> 8); }
という関数を用意して
if ((le(081, j) & le(j, 0x9f)) | (le(0xe0, j) & le(j, 0xef))) {
と書けば、& | ~ >> の 4種類のビット演算子を使ったことになります。