×

らずらいと姫の挑戦日記(第36回)~文字列~

2017-02-07

文字列は配列を使うと扱いやすい、ということがわかりました。しかし、文字列は一文字ずつ扱うと大変なので「文字列」として扱うための関数が準備されています。今回は、文字列の①コピー②比較③文字列を数字に変換の3つについて学びたいと思います。

12

コピー

1

A[n]という配列をB[n]にコピーします。

B[n]=A[n]  → ☓ まとめて配列をコピーすることはできません。

B[0]=A[0]・B[1]=A[1] → ○ 1バイトずつコピーすることは出来ますが、大変です。

まとめてコピーする方法

memcpy(B,A,sizeof(B)): AをBにBのサイズ分コピーする

2

memcpy(B,A,3): AをBに3バイト分コピーする

11

memset(B,0,sizeof(B)): BにBのサイズ分0(ゼロ)を書く

4

strcpy(B,”Hello”): 配列Bに”Hello”という文字列をコピーする

ただし、配列Bが”Hello”よりも短い場合にstrcpyを使用すると配列Bのサイズを超えて”HELLO”が書き込まれてしまいます。配列Bの続きのメモリは別の目的で使用されているデータが入っているので、他のデータを壊してしまう可能性があります。

7

strcpyは、明らかに文字列が配列よりも小さい場合にだけ使用してください。

strncpy(B,”Hello”,sizeof(B)): 配列Bに”Hello”という文字列をコピーする

“Hello”という文字列が配列Bより長い場合、配列Bのサイズまでしかコピーしません。strncpyはより安全にデータをコピーすることが出来ます。

比較用関数

8

Aが”HELLO”かを知りたい。

Aと”HELLO”を比較する方法は2つあります。

①strcmp(A,”HELLO”): Aを”HELLO”と比較する

②strncmp(A,”HELLO”,sizeof(A)): Aが”HELLO”かをAのサイズ分だけ比較する

いずれもnullコードが出てくるまで比較を続けます。文字化けが発生してしまいnullコードがなくなってしまった場合は、strcmpはnullが見つかるまで比較を続けますが、strncmpは配列のサイズで必ず終了します。

文字を数字に変換する

数値を文字列に変換するのは、strtolを使用するのが便利です。

strtol(文字列、NULL、0)

第一引数: 文字列が格納されている配列を指定します。
第二引数: 文字列の終了ポインタを指定します。NULLを指定しておくと自動認識となります。
第三引数: 文字列の数字の基数を指定します。0にすると自動認識となります。

例えば、

long l = strtok(“100″,NULL,0);
を実行すると、lには10進数の100が保存されます。

9

続いて、次の関数を実行してみると、lには10進数の16、16進数の0x10が入ります。

long i = strtol(“0x10″,NULL,0)

10

strtol関数は、10進数/8進数/16進数などの基数を指定しなくても自動で認識してくれるので、文字列を簡単に数値変換してくれます。

その他

そのほかに便利な関数は、strtokです。CSVファイル(カンマ区切り)の文字列を分解して、それぞれを数値に直す時に便利です。

色々と試してみました

今までのことをプログラムにまとめてみましたので、活用してみてくださいね。

プログラム

#include "hime_mojiretsu_ide.h" // Additional Header

#include "stdlib.h"

char A[32] = "HELLO";
char B[32] = {""};;

void setup() {
 // put your setup code here, to run once:
 int i;
 long l;
 char* data[8];
 Serial.begin(115200);

Serial.print("A[] = ");
 Serial.println(A);

 Serial.print("B[] = ");
 Serial.println(B);

// 文字列のコピー 
 A[8] = 1; // ダミーで9バイト目に1を代入しました。

 memcpy(B,A,sizeof(B)); // 配列Aを配列Bにコピーします。
 Serial.print("B[] = ");
 for(i=0;i<16;i++) // 9バイト目に1が入っています
 {
 Serial.print_long(B[i],DEC);
 Serial.print(",");
 }
 Serial.println("");

memset(B,0,sizeof(B)); // 配列を0にリセットします

Serial.print("B[] = "); // 配列Bが0にクリアされました
 for(i=0;i<16;i++)
 {
 Serial.print_long(B[i],DEC);
 Serial.print(",");
 }
 Serial.println("");

 strcpy(B,A); // 配列Aを文字列としてBにコピーします。
 Serial.print("B[] = "); // NULLコードまでしかコピーされていません。
 for(i=0;i<16;i++)
 {
 Serial.print_long(B[i],DEC);
 Serial.print(",");
 }
 Serial.println("");

memset(B,0,sizeof(B)); // 配列を0にリセットします

strncpy(B,A,3); // 配列Aを文字列としてBに最大3文字コピーします。
 Serial.print("B[] = ");
 Serial.println(B);

memset(B,0,sizeof(0));

// 文字列の比較を行います。
 if (strcmp(B,A) == 0) Serial.println("B = A"); // B="HE", A="HELLO"で比較を行います
 else Serial.println("B != A");

strcpy(B,A);
 if (strcmp(B,A) == 0) Serial.println("B = A"); // B="HELLO", A="HELLO"で比較を行いまs。
 else Serial.println("B != A");

// 文字列を数値に変換します。
 l = strtol("100",NULL,0);
 Serial.print("l = ");
 Serial.println_long(l,DEC);

l = strtol("0x10",NULL,0);
 Serial.print("l = ");
 Serial.println_long(l,DEC);

// 最後にCSV形式を数値に変換。
 strcpy(A,"100,0x100,0100");
 Serial.print("A = ");
 Serial.println(A);

data[0] = strtok(A,",\r\n"); // 配列Aをカンマ、または改行マークで区切ります
 l = strtol(data[0],NULL,0);
 Serial.print("data[0] = ");
 Serial.println_long(l,DEC);

 for(i=1;i<16;i++) {
 data[i] = strtok(NULL,",\r\n"); // 前回の続きから次のカンマ、または改行マークまでを切り出します。

 if(data[i] == NULL) break; // 文字列が終わったらおしまい

l = strtol(data[i],NULL,0);
 Serial.print("data[");
 Serial.print_long(i,DEC);
 Serial.print("] = ");
 Serial.println_long(l,DEC);
 }
}

void loop() {
 // put your main code here, to run repeatedly:

}

結果

13

Laz-princess_footer