diff --git a/assets/cls11.png b/assets/cls11.png new file mode 100644 index 0000000..45c3908 Binary files /dev/null and b/assets/cls11.png differ diff --git a/out/report-cls11.pdf b/out/report-cls11.pdf new file mode 100644 index 0000000..ddd6427 Binary files /dev/null and b/out/report-cls11.pdf differ diff --git a/out/report-cls11.synctex.gz b/out/report-cls11.synctex.gz new file mode 100644 index 0000000..a97f966 Binary files /dev/null and b/out/report-cls11.synctex.gz differ diff --git a/report-cls11.tex b/report-cls11.tex index cc172bf..59250ab 100644 --- a/report-cls11.tex +++ b/report-cls11.tex @@ -2,6 +2,7 @@ \usepackage{tex/preamble} \usepackage{tex/simple-title} +\usepackage{here} \reportauthor{柴田健琉} \reporttitle{情報処理2 - 前期第11回課題} @@ -16,12 +17,85 @@ この課題のプログラムは以下の環境での動作が確認されている: \begin{itemize} - \item{OS: Arch Linux, Linux 6.18.37-1-lts x86\_64} + \item{OS: NixOS 26.05 Yarara, Linux 7.1.2 x86\_64} \item{CC: GCC 15.2.0} \item{CFLAGS: \texttt{-g -O1 -Wall -Wpedantic}} \end{itemize} \section{課題 - 回文判定} + 入力された英文文字列が回文になっているか判定する\texttt{kaibun}関数を作成する. + \lstinputlisting[language=C,title={回文判定プログラム}]{./src/cls11/main.c} + + \subsection{実行結果} + + \begin{figure}[H] + \centering + \includegraphics[width=12cm]{./assets/cls11.png} + \caption{回文判定プログラムの実行結果} + \end{figure} + + \subsection{処理の流れ} + + \subsubsection{\texttt{my\_strlen}関数} + + \begin{enumerate} + \item{\texttt{str}に対しヌルポインタチェックを実施し, エラーであれば異常値を返却する} + \item{変数\texttt{i}を宣言し, 0で初期化する} + \item{文字へのポインタ\texttt{str}から\texttt{i}分ずれたアドレスを指す文字がヌル文字でない, かつ\texttt{i}が最大文字カウント\texttt{max\_len}以下であれば, \texttt{i}をインクリメントする} + \item{条件を満たすまで3を繰り返す} + \item{\texttt{i}を返却する} + \end{enumerate} + + \subsubsection{\texttt{to\_lower}関数} + + \begin{enumerate} + \item{\texttt{str}に対しヌルポインタチェックを実施し, エラーであればサブルーティーンを早期終了させる} + \item{カウンタ変数\texttt{i}を0から文字列の長さ\texttt{sz}まで3を繰り返す} + \item{文字型ポインタ\texttt{str}から\texttt{i}分ずれたアドレスを指す文字がASCIIの'A'以上, 'Z'以下であるならば, 十六進数値0x20を足し, ASCIIの'a'から'z'の範囲にある文字に変更する} + \end{enumerate} + + \subsubsection{\texttt{strip}関数} + + \begin{enumerate} + \item{\texttt{str}と\texttt{dest}に対しヌルポインタチェックを実施し, エラーであれば異常値を返却する} + \item{変更後の文字列の長さを格納する整数型変数\texttt{ret\_sz}を宣言・初期化する} + \item{カウンタ変数\texttt{i}を0から文字列の長さ\texttt{sz}まで4を繰り返す} + \item{文字型ポインタ\texttt{str}から\texttt{i}分ずれたアドレスを指す文字がASCIIの'a'以上, 'z'以下であるならば, \texttt{dest}文字列に該当文字を追加し, \texttt{ret\_sz}をインクリメントする} + \item{\texttt{dest}文字列の終端にヌル文字を追加する} + \item{\texttt{ret\_sz}を返却する} + \end{enumerate} + + \subsubsection{\texttt{kaibun}関数} + + \begin{enumerate} + \item{\texttt{str}に対しヌルポインタチェックを実施し, エラーであれば論理偽を返却する} + \item{カウンタ変数\texttt{i}を0から文字列の長さ\texttt{sz}の半分まで3を繰り返す} + \item{文字ポインタ\texttt{str}の始点と終点から中央に向って\texttt{i}分ずれたアドレスが指す値が一致しなかった場合に論理偽を返却する} + \item{\texttt{for}ループを抜けたら論理真を返却する} + \end{enumerate} + + \subsubsection{\texttt{main}関数} + + \begin{enumerate} + \item{\texttt{buff}と\texttt{processed\_str}の2つそれぞれに\texttt{BUFF\_SZ} + 1文字分のメモリを確保する} + \item{標準入力から最大\texttt{BUFF\_SZ}文字の1行を取得し, \texttt{buff}に格納する} + \item{2でのエラー処理を行う} + \item{文字列\texttt{buff}の長さを取得, エラー処理も行う} + \item{文字列\texttt{buff}を\texttt{to\_lower}関数と\texttt{strip}関数で加工, \texttt{processed\_str}に格納} + \item{\texttt{processed\_str}に対し\texttt{kaibun}関数を適用, 結果を\texttt{isPalindrome}に格納} + \item{標準出力に\texttt{isPalindrome}の値を出力する} + \end{enumerate} + + \subsection{書く際の難点} + + Off by one errorで\texttt{kaibun}関数内のポインタ演算の処理が一発で通らず, 何回か修正・試行した. + + \subsection{想定されるバグ} + + 多くの関数で文字列の長さを指定する必要があるが, この長さを間違えると意図しない動作が発生してしまう. + 例えば, \texttt{kaibun}関数で1文字多く・少なく指定してしまったため, 回文であっても正常に判定されないという現象が考えられる. + + しかし, ユーザ側では長さの指定はできないので, プログラマが責任をもって記述することになる. \end{document} diff --git a/src/cls11/main.c b/src/cls11/main.c index 38b79c8..95f8349 100644 --- a/src/cls11/main.c +++ b/src/cls11/main.c @@ -3,8 +3,10 @@ #define BUFF_SZ 128 -// Lenght of string including null terminator +// Obtain the lenght of string int my_strlen(char *str, int max_len) { + if (str == NULL) return -1; + int i = 0; while (*(str + i) != '\0' && i < max_len) i++; @@ -14,6 +16,8 @@ int my_strlen(char *str, int max_len) { // convert ASCII CAPITAL CASE ALPHABETS into lower case alphabets void to_lower(char *str, int sz) { + if (str == NULL) return; + for (int i = 0; i < sz; i++) { if (*(str + i) >= 'A' && *(str + i) <= 'Z') { *(str + i) = *(str + i) + 0x20; @@ -23,12 +27,12 @@ void to_lower(char *str, int sz) { // remove every non-alphabet letters from string int strip(char *str, char *dest, int sz) { - int ret_sz = 0; - if (str == NULL || dest == NULL) { return -1; } + int ret_sz = 0; + for (int i = 0; i < sz; i++) { if (*(str + i) >= 'a' && *(str + i) <= 'z') { *(dest + ret_sz) = *(str + i); @@ -43,6 +47,8 @@ int strip(char *str, char *dest, int sz) { // check if string is a palindrome bool kaibun(char *str, int sz) { + if (str == NULL) return false; + for (int i = 0; i < (sz - 1)/2; i++) { if (*(str + i) != *(str + sz - i - 2)) { return false; @@ -53,28 +59,28 @@ bool kaibun(char *str, int sz) { } int main(void) { - char *b = (char*)malloc(sizeof(char) * (BUFF_SZ + 1)); // BUFF_SZ letters + null terminator - char *t = (char*)malloc(sizeof(char) * (BUFF_SZ + 1)); + // BUFF_SZ letters + null terminator + char *buff = (char*)malloc(sizeof(char) * (BUFF_SZ + 1)); + char *processed_str = (char*)malloc(sizeof(char) * (BUFF_SZ + 1)); printf("Input string: "); - char* res = fgets(b, BUFF_SZ, stdin); + char* res = fgets(buff, BUFF_SZ, stdin); if (res == NULL) { printf("Error while reading from stdin\n"); - return 0; + return 1; } - int len = my_strlen(b, BUFF_SZ); + int len = my_strlen(buff, BUFF_SZ); + if (len == -1) { + printf("Error on retrival of string length."); + return 1; + } + to_lower(buff, len); + len = strip(buff, processed_str, len); - printf("len: %d\n", len); - - to_lower(b, len); - len = strip(b, t, len); + bool isPalindrome = kaibun(processed_str, len + 1); - printf("len: %d\n", len); - - bool isPalindrome = kaibun(t, len + 1); - - printf("isPalindrome: %d\n", isPalindrome); + printf("isPalindrome: %s\n", isPalindrome ? "true" : "false"); return 0; }