0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【C言語】文字コードをずらして置き換えた文字列を出力する【備忘録】

Last updated at Posted at 2022-10-09

シーザー暗号:文字コードをずらして出力する

TechFULで解いていた問題のメモです。
修正に手間どったので、どのように解決したかの経緯と、新しく学んだ知識を書きます。

問題:
シーザー暗号化という文字列の暗号化方法があります。
これはすべての文字を、ある整数値(key値)だけ文字コードをずらした文字に置き換えるというものです。
標準入力から文字列strと、key値keyが与えられます。
この条件でシーザー暗号化された文字列cipherを出力してください。

(TechFULより引用)

条件:
key値は-10^9≦key≦10^9以下の整数
strは半角a~zで構成される0~256文字以下の文字列

負の整数を割った余りは負になる
ex)-17%4は1になる

最初に立てた方針:

・取得した文字に key%26 を足す
・'a'の文字コードより小さければ26を足す
・'z'の文字コードより大きければ26を引く

始め、char配列の宣言でコンパイルエラーが出ました。
以下のようなメッセージです。

main.c: In function 'main':
main.c:9:10: error: array size missing in 'str'
    9 |     char str[];
      |          ^~~

これは 配列strの要素数がなかった ことが原因でした。
後からscanf関数で文字列の長さが判明していない入力を受け取る場合でも、先に要素数を決めておく必要があります。

char配列の宣言には要素数が必要
char str[300];(入力よりも大きい要素数で用意)

サンプルケースはこれでうまくいきましたが、全テストケースにはまだ不正解が出ていました。

//不正解になったコード
    for (i = 0; strnlen(str, 258) > i; i++) {
        str[i] += key; //str[i]の値が128以上になってしまう場合がある!
        if (str[i] < 'a') {
            str[i] += 26;
        }
        else if (str[i] > 'z') {
            str[i] -= 26;
        }
    }

原因はchar型に格納できる値の範囲を考慮できていなかったことでした。
たとえば、'z'の文字コードは122であるため、key%26がとりうる最大値25が'z'に加算されると値は148となります。148は2進数8桁(2ビット)では表現しきれません。 符号付きchar型の最大値127を超えてしまい、間違った文字コードが代入されてしまう と思われます。

char型は2ビット(=1バイト)
10進数で0~127まで表現できる

ASCIIコード

ASCIIとは、2進数7桁で表せる整数値に文字や記号などが割り当てられた文字コードです。
0~127までの整数が割り当てられています。

文字 10進数 16進数
NULL 0 0x00
A 65 0x41
Z 90 0x5A
a 97 0x61
z 122 0x7A

大文字と小文字のコード差は必ず32になっているので、±32をすることで大文字と小文字の変換をすることができます。ASCIIコードについては以下のサイトを参照しました。
参照したページ:
http://www3.nit.ac.jp/~tamura/ex2/ascii.html

char 変数 = '文字'; でchar型の変数に文字コードを格納する
printf("%d\n", ch); で文字コード(整数)を表示する
printf("%c\n", ch); で文字コードに対応した文字を表示する

char配列の長さを調べる方法

strlen 関数を使います。
使用する場合は先頭に#include <string.h>を記述する必要があります。

strnlen(char配列, 最大値)
 strlen関数よりも安全。
 NULLで終わらなくても最大値までしか読み込まないようにできる。

_mbstrlen(char配列)
 日本語のかな文字などにも対応。
 #include <locale.h> #include <stdlib.h>を先頭に追加する。

参照したページ:
https://programming.pc-note.net/c/mojiretsu2.html

全テストケース通ったときのコード:

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

int main()
{
    //input
    int key, i;
    char str[257];
    scanf("%d %s", &key, str);
    key = key % 26;

    for (i = 0; strnlen(str, 258) > i; i++) { //場合分けした後でstr[i]の値を操作する
        if (str[i] + key < 'a') {
            str[i] = str[i] + 26 + key;
        }
        else if (str[i] + key > 'z') {
            str[i] = str[i] - 26 + key;
        }
        else {
            str[i] = str[i] + key;
        }
    }

    //output
    printf("%s\n", str);
    return 0;
}

2022/10/9実施
参照先:TechFUL

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?