このブログを検索

ラベル C言語 の投稿を表示しています。 すべての投稿を表示
ラベル C言語 の投稿を表示しています。 すべての投稿を表示

2022/03/13

strcpy

あるソースコードが以下のようになっていた。

#include <stdio.h>

int main(void)
{
        char dstaddr[] = "192.168.55.2";
        char srcaddr[] = "192.168.55.1";
 ....

宛先アドレス、送信元アドレスを引数で渡したいと思い、

int main(int argc, char *argv[])
{
        char dstaddr[] = argv[1];
        ...

などとやってみたがdstaddrにargv[1]の値が代入されない。

*dstaddr = *argv[1];

とすると、最初の一文字だけしか代入できない。

結論を言うと、strcpyでコピーすればよい。

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

int main(int argc, char *argv[])
{
        char dstaddr[];
        strcpy(dstaddr, argv[1]);
        ...

argvは文字型変数へのポインタの配列である。 dstaddr[]は文字型変数の配列である。

printf("arg1: %s\n", argv[1]);

とすると、ちゃんと引数に指定した値が文字列として、例えば hello とか、

表示されるので、あたかもargvという変数に文字列が格納されているかと思ってしまうが、

これはprintfが内部でヌルが出現するまでargvのアドレスをインクリメントして表示しているのである。

strcpyという関数も、ポインタあるいは配列をインクリメントして1文字ずつコピーしているだけである。


strcpyを自分で書いてみる

#include 

void mystrcpy(char *s, char *t)
{
    while (*s++ = *t++)
        ;
}

int main(int argc, char *argv[])
{
        char addr1[] = "192.168.1.2";

        printf("addr1: %s\n", addr1);

        printf("arg1: %s\n", argv[1]);

        printf("copy arg1 to addr1\n");

        mystrcpy(addr1, argv[1]);
      
      printf("addr1: %s\n", addr1);
}

実行結果

# ./a.exe 172.16.1.5
addr1: 192.168.1.2
arg1: 172.16.1.5
copy arg1 to addr1
addr1: 172.16.1.5

参考: 「プログラミング言語C」 カーニハン/リッチー

https://atmarkit.itmedia.co.jp/ait/articles/1703/01/news170.html

2022/02/26

c言語のchar

c言語のcharについて。

# cat cha.c
#include 

int main(int argc, char *argv[]) {

        char *c1;
        c1="a";
        printf("c1: %d %s\n", c1, c1);

        c1++;
        printf("c1: %d %s\n", c1, c1);

        c1="hello";
        printf("c1: %d %s\n", c1, c1);


        char c2;
        c2 = 'a';
        printf("c2: %d %c\n", c2, c2);

        c2++;
        printf("c2: %d %c\n", c2, c2);

        c2 = 'c';
        printf("c2: %d %c\n", c2, c2);

        return 0;
}


# ./a.out x
c1: 4196104 a
c1: 4196105
c1: 4196116 hello
c2: 97 a
c2: 98 b
c2: 99 c


charというのは「1文字」である。
1文字なので、"hello"とかを代入できない。

上記の例では、c1は char *c1
c2は char c2
と定義(宣言?)している。

注目すべきはc1, c2に代入するときの引用符で、c1は"", c2は''にしている。

ポインタ宣言(という言い方でいいのか)した場合は"", そうでない場合は'' である。

c1に'a'を、c2に"hello"を入れようとするとコンパイルでエラーになる。

char *c1;
としたときはc1はポインタなので、%dで表示するとその内容はアドレスになる。
char c2;
としたときはc2は文字なので、%dで表示するとその内容は文字コードになる。

c1はポインタなので、インクリメントしても未定義の値が表示される。
c2は文字なので、aをインクリメントするとaの次の文字コードであるbが表示される。

2008/10/24

ファイルを特定の文字列で分割する


cygtls::handle_exceptions: Error while dumping state (probably corrupted stack)

ある簡単なCのプログラムを実行したときに表示されたエラーである。

サーチしても全然情報がなくて、試行錯誤の結果原因はわかった。恥ずかしいことだが、openしていないファイルに書き込もうとしたことが原因である。

しかし、私は釈然としない。たしかに私の初歩的なミスではあるが、その時にどうして上記のようなエラーが表示されるのか、と。何がprobably corrupted stackだよ、と。

作ったプログラムは、あるファイルを分割するものである。

分割条件は、">>"で始まり、"<<"で終わる。
ファイルを読んで、">>"が現れたら出力ファイルを開き、"<<"が現れるまで読み込んだ行を出力ファイルに書き込む。
そして、"<<"が現れたらファイルを閉じる、というループである。

私は、">>"が現れない場合を考慮していず、その場合は読み飛ばさなけれならないのにopenしていないファイルに出力していた。

とりあえず、出力ファイルのopen/close時にフラグをオン・オフして、フラグがONの時のみ書き込むようにした。

最初、フラグの名前を"WRITE"にしたらエラーが出た。予約語だなと思って"write_flg"としたら、またエラーが出た。これも予約語なのかなと"www"にしたらようやくコンパイルが通った。

もうひとつ懸案事項がある。

このプログラムでは、ある条件で現れるログ内の行の文字列をファイル名としている。その文字列の長さは不定であり、その文字列に拡張子".log"を連結している。

strncpy(s2,buf+3,strlen(buf)-4);
s2[strlen(buf)-4]='\0';
printf("%s\n",s2);
sprintf(s, "%s%s", s2, EXT);
outputfile = fopen(s, "w");

このとき、strncpyで文字列をコピーしているのだが、開始位置が3で、文字列長は3+1=4である。この+1とは、改行コードのLFである。

">> ABC-1.2"+(LF)

という文字列から、

"ABC-1.2.log"

という文字列を作りたいのである。

一応これでうまくいっているのだが、改行コードがCR+LFになると、だめだ。そのときは、-5にしないといけない。これをどちらでも対応できるように、つまりCR+LFなら5,LFなら4とする方法はあるのか?


2007/12/18

ログファイルの分割

ある大きなログファイルがあって、決まった書式の文字列で区切られているものを分割するプログラムを作った。ファイルを読んで分割して書き出すのはすぐにできたのだが、そのファイル名を区切りに書いてある番号付の文字列にするところでてこずった。

区切りの文字列は">> ABC-12.6"というような文字列で、数字は項目番号である。この文字列の先頭の記号とスペースを除いたもの+".log"をファイル名にしたかった。まずてこずったのは"ABC-12.6"を切り取ることである。Excelの関数ではmidとかを使って切り取った経験はあるのだが、どうもうまくいかない。結局、問題は文字列の末尾にCR+LFがついていたことが理由だった。その2文字もlengthに含まれていたのだ。

次の難所は、ある条件でファイル名に余計な文字列が付加されることである。たとえば、"ABC-10.15"の次に"ABC-11.1"が来たときに、"ABC-11.15"となってしまう。前の文字列より短い場合に、前の文字列の末尾が残ってしまうのである。

調べた結果、strncpy関数は、コピー先の文字列より長い文字列をコピーした場合は終端文字が付加されるが、コピー先より短い文字列をコピーすると、終端文字が付加されないことがわかった。そのため、strncpy関数を使用するさいには常に終端文字を付加することが推奨されているようである。