C言語なら俺様に聞け! Part 64

このエントリーをはてなブックマークに追加
663
C言語で文字列を解析する関数を作りたいんですけど、
char同士の代入のあたりでコアダンプしてしまいます。
どうすればいいか教えていただけませんか?

$ cat whyerror.c
#include <stdio.h>
#include <stdlib.h>
int test(char ** string_ptr, char * string) {
    int len = 0;
    *string_ptr = (char *)malloc(sizeof(char));
    while (*string) {
        printf("%d: %c\n", ++len, *string++);
        *string_ptr = (char *)realloc(*string_ptr, sizeof(char) * (len + 1));
        **string_ptr++ = *string; /* ??? */
    }
    **string_ptr = '\0';
    return 0;
}
int main(void) {
    char * string;
    char * result;
    string = "this is test!";
    test(&result, string);
    printf("result: %s\n", result);
    return 0;
}

$ gcc whyerror.c -Wall; ./a.exe
1: t
2: h
Segmentation fault (core dumped)
664:03/09/18 20:16
最初間違って「C++相談室 part23」のほうに書き込んでしまいました。
http://pc2.2ch.net/test/read.cgi/tech/1062690663/269-274

以下、自レスより引用。
> /* ??? */ の一行が間違っていそうな気が
> するんですが、何がどう間違っているかが分からないんです。
> ポインタの扱い方を勘違いしているのかな?
> charにcharってそのまま代入してもいいんですよね?

で、274さんから
> ちなみになんで落ちるかっつーとreallocの第一引数がmalloc/reallocで確保された
> メモリ領域を指していないから。原因はstring_ptr++;
というレスを頂いたのでstring_ptr++しないように

*string_ptr[len-1] = *string;

としてみました。でもやっぱり同じです。

こんな漏れはPerlでも触ってたほうがいいでしょうか。。。
>>663
> **string_ptr++ = *string; /* ??? */
string が sizeof(char**) 分 ++ されているな
* と ++ の優先順位の問題

>>664
> *string_ptr[len-1] = *string;
これも (*string_ptr)[len-1] としないと駄目

ただ,何でこんな変なことやってるの?

char *test(char * string) {
    int len = 0;
    char *string_ptr;
    string_ptr = (char *)malloc(strlen(string)+1);
    while (*string) {
        printf("%d: %c\n", ++len, *string++);
    }
    return string_ptr;
}

じゃ駄目なの?
666665:03/09/18 20:41
>>665
誤: string が sizeof(char**) 分 ++ されているな
正: string_ptr が sizeof(char**) 分 ++ されているな

あと、ソースじゃ malloc や realloc の戻り値をチェックしてないけれど
ちゃんとチェックするようにな

char *test(char * string) {
int len = 0;
char *string_ptr;
string_ptr = (char *)malloc(strlen(string)+1);
if (string_ptr == NULL) return NULL;
while (*string) {
printf("%d: %c\n", ++len, *string++);
}
return string_ptr;
}

あと,sizeof(char) は言語仕様で 1 と決まってるからあまり意味がないよ
667665:03/09/18 20:42
うあ、ソースが大変なことに…
みんなどうやってインデントしているの?
668665:03/09/18 20:45
何度もゴメン、不慣れで…

char *test(char * string) {
 int len = 0;
 char *string_ptr;
 string_ptr = (char *)malloc(strlen(string)+1);
 if (string_ptr == NULL) return NULL;
 strcpy(string_ptr, string);  /* ← 抜けてた */
 while (*string) {
  printf("%d: %c\n", ++len, *string++);
 }
 return string_ptr;
}
>>663
プログラム中に ** なんてのが出てくるとろくなことがないので、
一時変数を導入して、プログラムをわかりやすくする。
*string_ptr = (char*)malloc(長さ);
*string_ptr = (char*)realloc(長さ);
なんてするかわりに

char* p;
p = (char*)malloc(長さ);
p = (char*)realloc(p, 長さ);
として p を使っておいて、
呼び出し側に帰る直前に渡されたポインタの先にpを書き込む。
*string_ptr = p;
return 戻り値;
こんなふうにすると見通しがよくなる。

p を戻り値にできるんなら、そのほうが良い。
670デフォルトの名無しさん:03/09/18 20:54
よくわからんが、>>663さんのやってることを極力変えないで文法が
正しくなるように、昨日K&R本を読み終えたばかりの僕ちゃんが直しました。
#include <stdio.h>
#include <stdlib.h>
int test(char **string_ptr, char * string) {
int len = 0;
char *p;
*string_ptr = (char *)malloc(sizeof(char));

p = *string_ptr;
while (*string) {
printf("%d: %c\n", ++len, *string);
*string_ptr = (char *)realloc(*string_ptr, sizeof(char)*(len + 1));
*p++ = *string++; /* ??? */
}
*p = '\0';
return len;
}
int main(void) {
char *string = "this is test!";
char **result;
test(result, string);
printf("result: %s\n", *result);
return 0;
}
671:03/09/18 20:55
>>665-670
懇切丁寧にありがとうございます!

>> **string_ptr++ = *string; /* ??? */
> string が sizeof(char**) 分 ++ されているな
> * と ++ の優先順位の問題

後学までに、これをそのまま使うとしたら、どこかに
カッコを付ければ動くようになるんでしょうか。
*(*string_ptr++)とか試してみましたが、うまくいきませんでした。

> ただ,何でこんな変なことやってるの?

今回のソースは簡略化しています。
もともと文字列を解析したくて関数を作っていました。
で、関数自体の返り値は何通りかの結果コードを
返すのに使いたいな、と思ったわけです。

ただ、変なソースなんだろうとは思います。
いままでRuby/Perl/Shellばかりで、
C言語の経験は全くありません。
ポインタ・メモリ周りは何冊も本を読んで
分かったようで全然分かっていません。。

これからもう少し実験してみます。
ありがとうございました。
>>671
> *(*string_ptr++)とか試してみましたが、うまくいきませんでした。
*(*string_ptr)++ですかね

char **string_ptr; と宣言したなら
string_ptr は char ** 型(これに++するとsizeof(char *)分進む)
*string_ptr は char * 型(これに++すると文字の位置が1つ進む)
**string_ptr は char 型(これに++すると文字のASCIIコードが1つ増える)
になります

* は ++ より優先順位が低いので(演算子の結合の強さの問題であって,演算の順序ではない)
*(*string_ptr++) では,やはり *( *(string_ptr++) ) となってしまいます

でもやはり>>669-670さんのやり方が一番だと思います

で,私にも後学のために2chでのインデントの方法を教えてもらえますか?
お前ら知ってたか?staticってのは、はじめ(start)からあるからstaticっていうんだぜ。rをつけると語呂が悪くなるから省略したんだと。
674:03/09/18 21:19
>>670
> char **result;
> test(result, string);
> printf("result: %s\n", *result);

これだと

  *string_ptr = (char *)malloc(sizeof(char));

のところでSegmentation faultになりました。

  char *result;
  test(&result, string);
  printf("result: %s\n", result);

にすると動きました。

なんでかよく分かっていないんですが、ご報告まで。

>>672
> 2chでのインデントの方法
&nbsp; で半角スペースほどの空白が空きます。
if (a > b) {
&nbsp;&nbsp;c = a;
}

if (a > b) {
  c = a;
}
>>674
>>674さんが正しい
main()の中で char **result; してtest()に値渡ししても,
実際に char * の領域が確保されているわけではないから
test()の中で*string_ptrで参照しようとしている所でアクセス違反になる

>>669>>670だったんですかね?
>>669で言ってることは正しいが,>>670の実装は不味すぎ

>   で半角スペースほどの空白が空きます。
thx
677676:03/09/18 21:31
実際に&nbsp;で半角スペースが空いてしまったわけだが…
どれどれ
<pre>は使えるのかな。

<pre>
main(){
printf("hello\n");
}
</pre>
>>678
だめじゃん
>>673
脳内辞典ですか?
まぁ、仮に語源がそうだったとしても、プログラムとは関係ないわな。
681:03/09/18 22:08
たびたびすみません。
やっぱりまだ変です。

$ gcc whyshort.c -Wall -ggdb; ./a.exe
1: t (1)
2: h (2)
3: i (3)
4: s (4)
5: (5)
6: i (6)
7: s (7)
8: (8)
9: t (9)
10: e (10)
11: s (11)
12: t (11)
13: ! (11)
result: this is tes

こんな具合で、最後の2文字がコピーされません。
ソースは次のとおりです:
682:03/09/18 22:08
$ cat whyshort.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int parse_num_list(char **string_ptr, char * string) {
   int len = 0;
   char *p;
   *string_ptr = (char *)malloc(sizeof(char));
   p = *string_ptr;
   while (*string) {
      printf("%d: %c ", ++len, *string);
      *string_ptr = (char *)realloc(*string_ptr, sizeof(char)*(len + 1));
      *p++ = *string++;
      printf("(%i)\n", strlen(*string_ptr));
   }
   *p = '\0';
   return len;
}
int main(void) {
   char *string = "this is test!";
   char *result;
   parse_num_list(&result, string);
   printf("result: %s\n", result);
   return 0;
}
>>680
トップページをヤフーからinfoseekに換えることを勧める。
辞書が揃ってるから。
質問なのですが、
関数の手前に!を付けるのって
if (!strcmp(array1.array2))
  ↑みたいな感じの
これってその関数の戻り値の真偽を逆にするって事で良いんですか?
>>684
Yes

strcmp を「文字列が異なっていれば真」を返す関数と捉えていれば
!strcmp は「文字列が一致すれば」と自然に理解できる

実際,戻り値が正か負かなんて気にすることも少ないしね
0か非0か,と認識しておいた方がいいと思う
qsort をつかったことがないらしい。
mergesortなら使ったことがあるらしい。
>>685
ありがとうございます。
入門書読みながらがんばってたのですが、どうもそういった細かい部分が
知っていて当たり前の知識とでも言うかのように割愛されているのです…
ですが、おかげで謎が解けました。
>>686
お前は文字列の「順序関係」と「等価性」のどちらを判定することが多いのか,と
690:03/09/18 22:53
>>681-682
自己レスです。

printf("(len:%i, s-ptr:%p, p-ptr:%p)\n", strlen(*string_ptr), *string_ptr, p);

としてポインタのアドレスを調べてみたら

$ gcc whyshort.c -Wall -ggdb; ./a.exe
1: t (len:1, s-ptr:0xa040408, p-ptr:0xa040409)
2: h (len:2, s-ptr:0xa040408, p-ptr:0xa04040a)
3: i (len:3, s-ptr:0xa040408, p-ptr:0xa04040b)
4: s (len:4, s-ptr:0xa040408, p-ptr:0xa04040c)
5: (len:5, s-ptr:0xa040408, p-ptr:0xa04040d)
6: i (len:6, s-ptr:0xa040408, p-ptr:0xa04040e)
7: s (len:7, s-ptr:0xa040408, p-ptr:0xa04040f)
8: (len:8, s-ptr:0xa040408, p-ptr:0xa040410)
9: t (len:9, s-ptr:0xa040408, p-ptr:0xa040411)
10: e (len:10, s-ptr:0xa040408, p-ptr:0xa040412)
11: s (len:11, s-ptr:0xa040408, p-ptr:0xa040413)
12: t (len:11, s-ptr:0xa040820, p-ptr:0xa040414)
13: ! (len:11, s-ptr:0xa040820, p-ptr:0xa040415)
result: this is tes

となりました。どうやら途中から*string_ptrとpとで
参照しているアドレス領域が食い違ってしまったようです。
もう一度やり直します。。。
>>690
最後まで p を使って string_ptr に反映するのは return 前にすればいい
692669 (≠670):03/09/18 23:05
int parse_num_list(char **string_ptr, char * string) {
   int len = 0;
   char *p;
   p = (char *)malloc(1);
   while (*string) {
      p = (char *)realloc(p, len + 1);
      p[len++] = *string++;
   }
   p[len] = '\0';
   *string_ptr = p;
   return len;
}
>>682
メモリの動的確保は予想以上に重いし神経使うので
できるだけ1度にやってしまった方がいいと思う

realloc で再確保してるのは何か意味があるの?
>>692
p = (char *)realloc(p, len+2);
じゃない?
695:03/09/18 23:21
>>669さんのレスをもう一度読みながら
試行錯誤したらできましたー!
>>669さん≠>>670さんだったみたいですね。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int parse_num_list(char **string_ptr, char * string) {
  int len = 0;
  char *p;
  p = (char *)malloc(sizeof(char));
  for (len = 1; *string; ++len, *string++) {
    printf("%d: %c ", len, *string);
    p = (char *)realloc(p, sizeof(char)*(len+1));
    p[len-1] = *string;
    p[len] = '\0';
    printf("(len:%i, ptr1:%p)\n", strlen(p), p);
  }
  *string_ptr = p;
  return len;
}
int main(void) {
  char *string = "this is test!";
  char *result;
  parse_num_list(&result, string);
  printf("result: %s\n", result);
  return 0;
}
>>690
strdup()は使えないのか?
697:03/09/18 23:26
>>692
ありがとうございます!
すっかり勘違いしていました。

>>693
もともと文字列を解析して必要な部分だけを
*string_ptrに格納して返すという関数を
作りたかったので、長さは最初は分からないんです。
まあ最初からある程度大きめにしておいてもいいとは思います。

これでようやく解析ルーチンに移れます。
698692:03/09/18 23:27
>>694
おっしゃるとおりです。
++lenを後ろに移動したときに、バグを入れちゃいました。
解析内容によってはもっといい解決策が存在するに10000ペリカ。
>>695
sizeof(char) が 1 になるのは言語仕様で決まってるよ
あと,malloc と realloc の失敗処理は入れた方がいいね
特に realloc の方
みんな言ってるように、1文字ごとにrealloc()するのは良くない。
realloc()は想像以上に重い処理だし、小刻みにrealloc()すると
ヒープの断片化も起きやすくなる。

必要な長さをあらかじめ計算して1回のmalloc()ですませるほうが良い。
702:03/09/18 23:36
>>699
そうかも。。。最初のプログラムなので練習もかねて
自分なりに考えて作ってみてから、
あらためて批評を請いたいなぁと思っています。
その節はよろしくお願いします。

>>700
そうですね。>>666でも指摘されていましたが、
読み流していました。ちゃんとやろうと思います。
>>702
多分 realloc を繰り返すより
string を2回走査する方が速い
>>702
ちなみに、どんな解析をしたいのよ?
ポインタへのポインタ **string_ptr を使う意図がわからんのだが
呼び出し側でわざわざ引数に & つけるならcharへのポインタでもよさげ
>>705
お前、ポインタを理解してないだろ。
>>706
禿同
>>705
アセンブラは結構わかってたりするだろ
アセンブラ知っててポインタがわからない?
どういうしと。
抽象化されるとアウト
漏れも**は多次元配列渡すときに使うもんだとおもってた
712ど素人:03/09/19 00:56
構造体についての質問です。

 まず、他の関数からの引数のInputで整数nが入力されます。
このときchar a, char b, char c のセットをnの回数分だけ
用意したいのですが、以下のような構造体を定義して
使用すればよいのでしょうか?

typedef struct _structA{
intn;/* structBの出現回数 */
structB*pStructB;
}structA;

typedef struct _structB{
chara[5];
charb[10];
charc[20];
}structB;



識者の皆様、ご指導よろしくお願いします。
713デフォルトの名無しさん:03/09/19 01:00
>>712
なんだかよくわからないけど、structB*pStructB;はポインタにする必要があるの?
アセンブリをアセンブルするアセンブラ。覚えとけ。
715713:03/09/19 01:02
というか、全てstructAのメンバーにしてもよさそうな・・・
>>712
それでOK。

関係ないが、struct _structB のようにアンダスコアをつける必要はない。
typedef struct structA { ........... } structA;
として何の問題もない。
>>716
つーかstructのあとのstructAはいらん。自己参照型のポインタをもつなら必要だけど。
>>712
若干の修正が必要かもしれんが、ええんでないの。
何に使うかわからんが、とりあえず
作るとすればこんなかんじかな・・・

structA* CreateFunc(int n)
{
structA *datA = (structA *)malloc(sizeof(structA));

datA->n = n;
datA->pStructB = (structB *)malloc(sizeof(structB) * n);

return datA;
}
720713:03/09/19 01:39
ああそうか。structBの配列を動的に作成してそれへのポインタをいれるつもりなのか。
ならそれでOKだな。
721713:03/09/19 01:40
>>719
やっぱりそうか。
722713:03/09/19 01:47
いや、OKじゃない。型structBの定義はstructAの定義よりも上に書かないとエラーになる。
structB *pStructB; ←ここで
まぁどうでもいいことだが、
structB
とかは境界を意識して
改良するも良。
>>722
前方参照って知ってる?

//取り合えず型がある事をコンパイラが分るように
typedef struct structB;

typedef struct _structA{
intn;/* structBの出現回数 */
structB*pStructB;
}structA;

typedef struct _structB{
chara[5];
charb[10];
charc[20];
}structB;

725713:03/09/19 05:02
>>724
>>712のどこにそれがある?
>>713
712は構造体を提示しているだけでコードを提示している訳じゃないでしょ?

>型structBの定義はstructAの定義よりも上に書かないとエラーになる。
この頭悪い表現を突っ込まれてるるんでしょ?
構造体の定義をAとB逆にしろって意味に取れる。
>>726
「型」structBの定義と書いているんだが・・・
わざわざ>>724のように書いているとはとてもじゃないけど思えない。

↓ならまだ考えられるけど
typedef struct _suructB struct B;
typedef struct{
・・・
}structA;
struct _structB{
・・・
};
728727:03/09/19 05:40
typedef struct _suructB struct B;はtypedef struct _suructB structB;の間違い
typedef float[4] RGBA;
RGBA image[100];

という型の配列を16バイトのアライメント境界上に
置くためにはどのような構文を書けばいいのでしょうか?
Cというよりコンパイラの実装の問題なんでしょうか?
使用してるのはVC++7.0です。
730デフォルトの名無しさん:03/09/19 09:09
Win32 をサポートするプロセッサにおけるアライメントは適切に処理されます。

データ型 アライメント
char バイト境界に配置
short (16 ビット) 偶数バイト境界に配置
int および long (32 ビット) 32 ビット境界に配置
float 32 ビット境界に配置
double 64 ビット境界に配置
構造体 いずれかのメンバの最大のアライメント要件に合わせる
共用体 最初のメンバのアライメント要件に合わせる

なんで
16バイトアライメントにするには
pragma使ってやるしかないかも。
>>729
new や mallocは確か16バイト単位だったような記憶もある。試してみたら?
>>729
> Cというよりコンパイラの実装の問題なんでしょうか?

その通り。
image[100]
のあとにアライメントオプションとか表記すればいけなかったけ?

floatになってるのはSSEか何か使うってこと?
ありがとーございます。それから
typedef float RGBA[4];
こうでした。間違えましたすいません。mallocは16バイト境界には
置いてくれないみたいです。アライメントのオプションとか探したんですが
あまりピンと来るのが見つけられなかったので、多めにmallocで確保して
#define ALIGNE16BYTE(address) ( (void *)( (unsigned long)(address) + 16 - ((unsigned long)(address))%16 ) )
こんなマクロ関数でちょこっとずらして使うことにしました。
>>736
そうです。そっちの方でもわからん事が出てきてるんですが
それはこのスレの趣旨ではないので・・・
もまえら、ヘッダファイルの

#include <admmsg>

って何ですか?

ちょっと調べてみたが分からんので解説できる人おながいします
.hが付いてないからC++じゃないか?
738736:03/09/19 15:23
>>737

スマソ、."h"ついとった・・・

ググッて見ても分かんねぇ・・・

_| ̄|○
最近安易に使うやつがいるけど、これムカツクんだよね俺。→_| ̄|○
     |_       ○
     _|     |_| ̄
○|_| ̄○  |_|__| ̄|○|_| ̄_| ̄|○
○_| ̄|○  _|_|○○|_| ̄ ○| ̄| |_
| ̄○|_| ̄  ○ ○_| ̄|○○| ̄|_○ _|
 ̄|_| ̄|○  ○|_| ̄_| ̄|○○| ̄|_○
_no
>>736
admmsg.hの中身見てみれば?
743デフォルトの名無しさん:03/09/19 22:05
>>735
アライメント
#pragma pack(1)だったような・・・
744● ◆65BWNgLL2E :03/09/19 23:17
昨晩>>663-704あたりでお相手いただいた者です。

あのあと、本来欲しかった関数を書いてみました。
http://www.geocities.jp/ohmycode/upload/20030919/numlist.c

int parse_num_list(char **string_ptr, char *string, int max_len);
max_len: リストの最大長。0 なら無制限 (= realloc を使う)

/* Example Code */
char string[] = "1-3,30,5-3";
char *result;
if (!parse_num_list(&result, string, 0)) {
   while (*result) {
      printf("%d ", *result++);
   }
}

"1-3,30,5-3"という入力から"1 2 3 30 5 4 3"というリストが得られます。
扱いたい数値はせいぜい0-100程度なので char 配列に格納しています。
素直に int にでもしたほうがいいかも知れませんが。。。

ソースを見て何かお気づきになった点などあればお聞かせ願えますか?
745● ◆65BWNgLL2E :03/09/19 23:24
あと、もっと簡潔に (or わかりやすく) 同じことを実現する方法などあれば知りたいです。
parse_num_list()の第2引数にconst付けた方がよい。
int parse_num_list(char **string_ptr, const char *string, int max_len);
747デフォルトの名無しさん:03/09/19 23:29
cファイルをプラウザで見れるような設定ってIEにありますか?
あったら教えてください。
748● ◆65BWNgLL2E :03/09/19 23:32
>>746
なるほど、そういう風にすれば安全であるばかりか、
関数を使うときに変えられずに済むことが一目瞭然ですね。
ありがとうございます!
>>744
あー、1-3-5,30,2みたいな文字列を解析するツールなら作ったなぁ。
逆順はなしってのと1-3-5-7みたいな連鎖もできるってのが違うけど。
確かハイフン処理の関数を全体処理の関数から呼ぶ形だった気がする。
複雑さの度合いは似たようなもんかもしれない。
つーか、少なくとも私にはそんなに大きな関数は作れない。
750● ◆65BWNgLL2E :03/09/19 23:42
>>749
藤原博文さん http://www.pro.or.jp/~fuji/ の本だったかに
関数は一画面内に収めるべし、100行を超えてはいけない、
とか書かれていたのを思い出します。。

一機能でまとまってるしいいかな、と思ってたんですが、
分解するとしたらたとえばどのへんを切り出せるんでしょうか。
>>745
細かいけど,sizeof(char) はいらないよ
あと,fgetsの引数でsizeof(string)-1の-1はいらない
752● ◆65BWNgLL2E :03/09/19 23:49
>>751
昨日から何回も指摘されていたんですが、
まだ慣れていないので何を意図しているのかを
示しておかないと不安でsizeofを残してました。

fgetsは、どっかのサンプルを真似しました。
-1はいらないんですね。。
>>745
reallocの失敗時にメモリリークするがいいのか?
>>752
分からないときは慎重にすべきだが,fgetsはnを与えたらn-1まで読み込むと規定されている.
755デフォルトの名無しさん:03/09/19 23:53
というか、
まず最初に",\n\r"など
strtokで抜き取ったあとハイフンチェック
とかはどう?
756● ◆65BWNgLL2E :03/09/19 23:53
>>753
ほんとだ。。こういう場合はきっと呼び出し側ですぐに
exit(1)するはずなので実用上は問題が起きないのかも
知れませんが、freeしておかないといけないんですね。

>>754
なるほど。一つ学習しました。
757● ◆65BWNgLL2E :03/09/19 23:54
>>755
どこかにstrtokは絶対に使うな!とか書いてあったんです。。。
>>745
strtokか何かで , で分けた後,
別の関数で, 30 や 1-3 の処理をした方がいいと思う.
あと,数字の処理も atoi か何かで.
オーバーフローが心配なら,先に atof で変換して INT_MAX と比較すればいい.
シングルスレッドなら問題ないけど。
>>757
じゃあ,strtok_r を使え
man strtok に
これらの関数は絶対に使用しないこと。
とか書いてあるな.
まあ,ちゃんと理解して使え,ということだ.
762● ◆65BWNgLL2E :03/09/19 23:59
あった、ここだ。

http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strtok.3.html
> char *strtok(char *s, const char *delim);
> char *strtok_r(char *s, const char *delim, char **ptrptr);
>
> これらの関数は絶対に使用しないこと。
> もし使用する場合は、以下のことに注意すること。
> ・これらの関数はその最初の引数を変更する。
> ・これらの関数は const な文字列では使えない。
> ・終端文字はすべて \0 になってしまう。
> ・strtok() 関数はパーズに静的バッファを用いるので、スレッドセーフでない。
>  もしこれが問題になる場合は strtok_r() を用いること。

「これらの関数は絶対に使用しないこと」って書いてあったから
怖くて使えませんでした。。strtok_rなら問題ないんですか?
>>762
これ「ら」の
>>762
strtok_r
いや,マルチスレッド対応してるだけで,実体は同じだ.
内部でstatic変数を使用している関数はスレッドセーフではない,ということだ.
getsと違ってきちんと理解していれば使ってもいいと思うけどな。
>>762
strtok は引数に与えた s を破壊してしまうから,
strtok を使う前に別のバッファに文字列をバックアップする必要がある,ということだ.
それを理解しておけばいい.
作業用のローカルバッファに文字列コピーして
やれば、ソースを壊さなくてすむ。

マルチスレッドなら・・・しゃあない。
>>767
ソース=元の文字列?
769● ◆65BWNgLL2E :03/09/20 00:07
そうですか、別のメモリ領域に文字列をコピーして
strtok_rを使えば問題はないわけですね。

それでは明日はstrtokを使ってどのくらい短くなるか
やってみたいと思います。
>>744
realloc しなくてもいいように,一度文字列を走査して必要なサイズを確かめるべきだと思う.
realloc は想像以上に重い.最悪,関数全体で使用する時間の80%くらい持っていく.
771デフォルトの名無しさん:03/09/20 00:08
>>769
strtokでいいって・・・どうせシングルスレッドだろ?
それなら標準関数を使った方がよい。
>>762
スレッドセーフなら問題ない
スレッドアンセーフでも、単一のスレッドでのみ動くのであれば問題ないが、
将来にわたってそうであることは保証できないので危険である。
いずれの場合もstrtok()の注意点に十分気を払う必要がある。

しかしstrtok()はかなり便利である。

一般にはスレッドアンセーフな関数は単一スレッドでのみ動くことが担保されていれば
大丈夫だが、OS内でも使われている可能性があり(OSのバグ)、トラブルに巻き込まれることがある。
>>771
一応 strtok_r も POSIX 標準のようだが…
774デフォルトの名無しさん:03/09/20 00:10
>>773
標準関数と言ったらPOSIXじゃなくてCの標準関数のことだろ。
ああちなみにC99はしらん。
>>772
まじ!?
ということはlocaltimeもOSによってはまずいの!?
776● ◆65BWNgLL2E :03/09/20 00:13
>>770
第三引数のmax_lenを決め打ちにしてしまえばreallocはしません。
max_lenが0のときだけreallocします。
必要なサイズを確かめていたら2回同じ解析を
しなきゃいけませんよね、、、

あ、>>703さんの
> 多分 realloc を繰り返すより
> string を2回走査する方が速い
っていうのはそういう意味だったのか。
>>776
ところで、環境(OSとかコンパイラとか)は?
>>775
それは知らんが、usleep()はやばかった。
>>768
ういうい。


>>769
あとは、他の方々もいってるとおり
ちびちびreallocすると処理重くなるので
大胆にひろげときなさい。
780● ◆65BWNgLL2E :03/09/20 00:18
>>777
CYGWIN_NT-5.0 1.3.22(0.78/3/2) 2003-03-18 09:20
gcc (GCC) 3.2 20020927 (prerelease)
です。

>>779
だって、"1-100,1-100,1-100,1-100,1-100"とかやられたら
幾らあっても足りませんよぅ。
>>778
select を使うんだ!
>>780
それか。じゃあ多分strtok_rはあるな。
783● ◆65BWNgLL2E :03/09/20 00:23
>>782
一応Unix/Linux(GCC)でもWindows(Visual C++)でも
動くようなコードを書きたいんですが、
でもPOSIX標準なら最近のコンパイラは大丈夫ですよね?
>>780
小問題に分割する方法は分かるよな

例えば,四則演算の解析だって
式 ::= 項 + 項
項 ::= 因子 * 因子
因子 ::= 数 | ( 式 )
とか定義して,式を解析するルーチン,項を解析…,とやるよな.

今回も,
リスト ::= 項 { , 項 }
項 :: = 数 | 範囲
範囲 ::= 数 - 数
って小問題に分けられるよな?
>>781
いやnanosleep()を使った。
786779:03/09/20 00:28
んじゃ、
連結リストを使って
初出の数字のみ、連結リストに加えていくってのはどう?

最終的に出来たリストは煮るなり焼くなりと。

realloc頻発よりは早いんでないかな。
787● ◆65BWNgLL2E :03/09/20 00:31
>>784
あ、なんかXMLのDTDなんかで似たような概念を
目にしたような気が・・・。

でもどうすればそのルールに基づいて
解析できるのかピンときません。
なにぶん知識がないものですみません。。。

演算の解析なら「はじめてのアルゴリズム入門」にでも
載ってたかな? 明日会社に行って見てみます。
788● ◆65BWNgLL2E :03/09/20 00:34
>>786
同じ数値は何回出てきてもいいように、
かつ順番も保持するようにしたいんです。

ふと思ったんですが、毎回1ずつreallocするよりも
n回ごとにnずつreallocしたほうが
ぐんと早くなるかも知れませんね。
最後のほうは多少無駄になるかも知れないけど、キニシナイ。
789786:03/09/20 00:39
>>788
いや、そういうことを>>779
あたりで言ってたんだがw

最後の方の無駄は気にしない
というかそんなもんです。
>>788
reallocにかかる時間に比べたらそんなものなんてことない。
>>788
縮小方向のreallocは普通失敗しないが?
792791:03/09/20 00:43
意味が分からなかったな
余分に取った領域は最後に縮小すればいいんでない?
>>787
(拡張)BNF記法というんですよ

「リスト」を解析する関数
「項」を解析する関数
「範囲」を解析する関数
「数」を解析する関数

を作ってそれらが内部から別の関数を呼ぶのですよ
794デフォルトの名無しさん:03/09/20 00:48
>>787
明日も会社か・・・
ガンガレ若者よ!
出たぁバッカス。
796793:03/09/20 00:53
「リスト」を解析する関数は strtok で , 毎に「項」に分割して
「項」を解析する関数を呼ぶ.

「項」を解析する関数は「項」が「範囲」か「数」か区別して
「範囲」を解析する関数と「数」を解析する関数を呼ぶ.

「範囲」を解析する関数は - の前後で「数」に分割して
「数」を解析する関数を呼ぶ.

「数」を解析する関数は atoi などで文字列から数値へ変換する.

と,まあこんな感じです.
もちろんそれぞれの関数内ではエラー処理(構文エラーなど)が入ります.
797● ◆65BWNgLL2E :03/09/20 00:58
>>792
なるほど、そうですね。

>>793>>796
BNF記法・・・なんだか聞いた覚えがあります。
前に読んだhyuki.comさんの「Java言語で学ぶ
デザインパターン入門」のInterpreterの章に
そんなのが出てました。
なんとなく概念は分かってきたような気がします。

それでは、そろそろおやすみなさい。
今日はありがとうございました。
それにしてもいろいろな本を読んでるね
PGの鑑やね
799質問です・・:03/09/20 01:23
以下は「3の倍数のアドレスに境界調整されたオブジェクトへのポインタを関数に渡す」
ことを意図したプログラムですが、何か問題があるでしょうか?
#include <stdio.h>
void showValue(long* value);
int main(void){
long surplus,*p;
unsigned int address;
char temp[40];
int alignment=3; /* 3バイトアライメントの場合 */

address=(unsigned int)&temp[0];
surplus=address%16;

if(alignment>16) return 1;

p=(long*)&temp[16-surplus+alignment];/* 3の倍数のアドレスに境界調整する */
*p=1000000;

showValue(p);

return 0;
}
void showValue(long* value){
printf("value addr=%p\n",value);
printf("value=%d\n",*value);
}
800
>>799
CPUによっては4バイトアライメントにあっていないアドレスに32bitアクセスすると
例外が発生する場合がある。
あくまでもsizeof(long)の幅でアクセスするので、3バイト単位ではアクセスされない。
説明が半端だ。

例外が発生する場合があるのではなくて、CPUによっては必ず例外が発生する。
CPUによっては、2回に分けてアクセスするので例外は発生しないがパフォーマンスが落ちる。
>>802
言いたいことは解るが、ここのスレタイに照らすと801の説明が正しいんでない?
Cの規格上は未定義の動作であって処理系定義ではないのだから。
つーと801も最後の1行はおかしいんだが。
804デフォルトの名無しさん:03/09/20 23:20
const int a ;

int const a ;

のどちらが正式な宣言なのでしょうか?

const int a ;
が一般的に使われているような気がしますが・・・
>>804
const int* a ;
int* const a ;
の場合を考えれば、
const int a ;
だろ。
>>804
どちらも正しい。
そうだね、漏れも前者の書き方するし、よく見るような気がするね。
807デフォルトの名無しさん:03/09/20 23:32
でも後者の方が仕様に忠実ですよね?
>>805 からすると、>>807 だよな。
>>807
どちらも正しいのに、なぜ後者の方が忠実だと思うの?
>>808
わるいが、805は全く見当違い。
ポインタが絡む場合、*の前にconstが書かれているのか*の後ろかで、何がconstなのかが違う。
const int* a ;
は、aが指す内容がconst、
int* const a ;
は、aがconstだ。
>>809
いま
「エキスパートCプログラミング」
読んでいる最中なのですが、それを読んでいるとそのような気がしたので・・・
>>810

> わるいが、805は全く見当違い。
>>810 が見当違い(w

const int* a ;
int* const a ;
が違うのを踏まえた上で

const int a ;
int const a ;
は同じ意味になるんだけどって話でしょ
>>805
const int*

int const *
と同じ。
int* const
とは違う。
宣言についての質問者ですが、みなさんありがとうございました。
なんとなくわかった気がします。
>>812
大丈夫か?
>>812

>>805をどう読むとそう解釈できるのか、
マジで分からんのだが。
レベル低〜
>>817
別に、お前は来なくていいよ。
ここは質問スレなわけだが。
const int * const * const * const ppp;
int const * const * const * const ppp;

もまいらどっちが筋通ってると思う?
既に筋が通ってても意味が無いと思う。
>>820
何っ!
健全性定理が破綻しているというのか…
ザコめが...つまらん!
>>822
理解できてないだろ?
>>823
ゲーーーーーーーーーーーーーーーーーテルか?
825sage:03/09/21 01:34
すみません、全く初心者で樹木のシミュレーションを始めたいのですが
簡単な分枝をC言語で書いたものって何処かのサイトに
ありますでしょうか
樹木のシミュレーション??
簡単な分枝??
C言語の問題と、特定のアルゴリズムの問題はわけて考えろよ。
おそらくスレ違いだな。
もう少し、具体的なプログラムが組めるようになったら、またここへ来な。
それと、何が初心者なのかな?
プログラミングか、Cか、樹木のシミュレーションか。
おそらく、全てなんだろうけどな。
>801,802,803
回答ありがとうございました。
実行させるコンピュータのアライメントを確認してみます。
>826
全くもっておっしゃるとおりです。
その具体的なプログラムを書くためにはどのような勉強をすれば
いいのかわからず、やる気だけが先へいってしまい書き込んでしまいました。

なんとか自分で頑張ってみます。
異常終了する可能性がある関数を定義します
その関数の正否を戻り値で返すとして
どのような戻り値にすればいいと思いますか?

1. 正常終了時:非0, 異常終了時:0
真偽値を返す関数との親和性が高くなります
if ( function1() && function2() ) exit(EXIT_SUCCESS); のような使い方ができます

2. 正常終了時:0, 異常終了時:非0 (または負値)
異常終了時に複数のエラーコードを返せます
if ( function1() || function2() ) exit(EXIT_FAILURE); のような使い方ができます

適材適所だとは思いますが,こういうときに 1. 2. を使い分ける
という指標があれば,混乱が少なくなると思うのです
どうかご意見をお聞かせください
>>829
自分でもそれぞれのメリットがわかっているみたいだから、
それ以上のアドバイスは出てこないんじゃなかな。

どうでもいいところで神経質に悩んでるようだと・・・、
重要な問題が見えてこないこともあるから気をつけてね。

あっ、俺だとその場合はね、正常終了は0で異常終了は負だね。
理由は、あとで複数のエラーコードに対応させたくなる場合もあるからかな。
C++だと、例外で対処できるんだけどなぁ。
831712:03/09/21 02:14
遅レスとなってしまいますが、
ご回答ありがとうございました。
>>829
自分で答え言ってるから、それ以上言うことがない。

ちなみにプログラムがエラーを返すのは異常終了ではない。
異常終了とは例えば記憶保護例外のようにプログラムの仕様に定義がない現象が
原因で終了することで、仕様に従ってエラーを返す動作は正常終了に分類される。
>>829
もっとトリビアルにしたほうがメンテナンス制は高いので
変なとこで悩むより、初心者が見て判りやすいコードにした方がよい。
あと、統一してればどちらでも良い。
まちまちにすると自分でもわからなくなる。

と思う。
>>833
初心者が理解できる必要があるコードって? サンプルか??
>>829
迷うところですね…

個人的にやってるのは、

・戻り値に含むのが成功か失敗かだけの場合
 成功:0 失敗:-1(or それ以下でエラーコード)
例:
 if (Initialize()) { /* 失敗〜 */ }

・戻り値になんらかの値を含む場合(特にポインタを戻す場合)
 成功:具体的な値 失敗:0
例:
 if (fp = CreateFile()) { /* fp使う */ }
 else { /* ファイルつくれねー */ }

・関数が何かを判定する場合(Is〜な関数名にする場合)
 成功:非0 失敗:0
例:
 if (IsEmpty(fp)) { /* どーもfpは空っぽらしい */ }

という具合ですかね?
まあ成功で非0の方に統一した方が混乱がなくていいかもですが…
>>829が示しているような長所短所をふまえた上でまだ統一とか言ってるのは不毛だね。
837● ◆65BWNgLL2E :03/09/21 12:54
皆さんのアドバイスを参考にしてnumlist.cを作り直してみました。
前よりもかなり長くなってしまいましたが・・・。

http://www.geocities.jp/ohmycode/#20030921

>>793>>796さんの言われたように
・「リスト」を解析する関数
・「項」を解析する関数
・「範囲」を解析する関数
・「数」を解析する関数
を作りました。

ついでに、簡易Unit Testを書いてみました。
Rubyのtestunitを思い出しながら自分流に作ってみたんですが、
C言語でUnit Testを実装する標準的な方法ってありますか?

何かお気づきのことがあればご指摘いただければ嬉しいです。
838● ◆65BWNgLL2E :03/09/21 13:01
あと、strtok_r の使い方がよく分かっていません。
こんな感じでいいんでしょうか。

char *strtok_buf = NULL;
char *strtok_ptr = NULL;
char *strtok_ptrptr = NULL;

strtok_buf = (char *)malloc(strlen(string)+1);
if (strtok_buf == NULL) {
   return(ERR_ALLOC_FAIL);
}
strcpy(strtok_buf, string);

strtok_ptr = strtok_r(strtok_buf, "-", &strtok_ptrptr);
/* いろいろ処理 */
free(strtok_buf); strtok_buf = NULL;

strtok_ptr を解放しなきゃいけないのは分かるんですが、
strtok_ptrptr は解放しなくてもいいんですか?
free(strtok_ptrptr)するとたまにStackdumpすることが
あったのでしていないんですが。。
そもそも、「関数自身が持つ静的バッファを使う代わりに
ユーザーが確保したバッファの char* ポインタを要求する。
このポインタである ptrptr 引数は、同じ文字列をパーズ
している間は同じ値にしておかなければならない。」と
書いてあるので、自分でmallocしておく必要はないんでしょうか?
NULLでも動いているのでいいのかな、と思ってしていないんですが。
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strtok.3.html
進めたものはmallocが返したものと異なるんだからfreeに渡しちゃまずいだろ・・・
840● ◆65BWNgLL2E :03/09/21 13:12
>>839
ん?ひょっとしてstrtok_ptrptrってのはstrtok_bufの
あるアドレスに対するポインタってことですか?
なんか勘違いしていたような。。。
841● ◆65BWNgLL2E :03/09/21 13:13
>>838
あと、
>strtok_ptr を解放しなきゃいけないのは分かるんですが、

>strtok_buf を解放しなきゃいけないのは分かるんですが、
の誤りでした。
>>838
strtok_ptrptr っていうよりは strtok_bufptr って呼ぶべきじゃないかなぁ?
strtok_buf の現在位置を持っている変数だから

で,strtok_r 内部でも strtok_ptrptr に対して malloc しているわけではない
(strtok_buf の現在位置を保存しているだけ)
ので,free で解放するのはまずい
>>840
そういうこと。
strtokでは関数内の静的変数に記憶させておくものをstrtok_rでは再入可能にするために呼び出し側に(ポインタを使って)返す。それがstrtok_rの第三引数。
だからそれはbufが指す配列のどこかを指している。
>>842
strtok_buf の現在位置

strtok_buf 内での現在位置(次のトークンが strtok_buf 内のどこから始まるかを保存)
845● ◆65BWNgLL2E :03/09/21 13:19
>>842
ようやく分かったような気がします。

http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strtok.3.html
に char *strtok_r(char *s, const char *delim, char **ptrptr);
とあったので、ptrptrは意味も分からずそのまま使ってました。。
>>837
最初 scope って何のことだろなと思っていたら「範囲」のことだったのね
range くらいにしてくれると思っていたのだが
847● ◆65BWNgLL2E :03/09/21 13:21
>>846
英語が苦手なもので、英辞郎で「範囲」を調べました。

ambit●area●bound●circle●circuit●compass●confine●coverage
●dimension〔【語法】通例、複数形〕●domain●extend●extent●incidence
●pale●plus or minus●province●purview●radius〔【複】radii〕●range
●range of observations●realm●region〔【略】reg.〕●scope●scouth
●span●spectrum●sphere●terrain●tether

で、なんとなくよさげなものを選んだというわけです。
他の関数名・変数名・コメント等も全部そんな感じです。
>>837
numlist.c 外部で使用しない関数は static にするってのはどうよ?
849● ◆65BWNgLL2E :03/09/21 13:47
>>848
そうですね。
本来、外部から呼び出すのは parse_num_list と errmsg_num_list
だけなので、あとは static にしてもいいかと思います。
でも、そうすると関数の単体テストはどうしましょうか。。
C言語での標準的方法って存在しないんでしょうか。
>>849
標準的方法は知らないが…

numlist.c に main 関数を作って #ifdef __NUMLIST_C__ 〜 #endif
とかで囲んでおくというのはどうだろう?
>>837
errmsg_num_listで変換指定子がひとつもないのにsnprintfを使っているのはなぜ?
それと、その関数は文字列リテラルの先頭アドレスを返せばいいと思う。
もしも呼び出し側で書き換えることがあるのなら、呼び出し側が用意したバッファに書き込むようにするのが良いと思う。

char *errmsg_num_list(int errnum) {
static const char *msglist[]={NULL,NULL,"memory allocation failed!",・・・,"invalid character!"};
return (errnum>=ERR_ALLOC_FAIL&&errnum<=ERR_INVALID_CHAR)?msglist[errnum]:NULL;
}
↑errnumが連続していなければswitchで。
852● ◆65BWNgLL2E :03/09/21 14:09
>>850
なるほど、PerlやRubyでの

if ($0 eq __FILE__) {
# test code
}

と似たような感じで、単体テストができますね。
今後はその方法を使ってみたいと思います。
>>851
msglist を static にしなければならないのが痛いな…
あと,その例で
(errnum>=ERR_ALLOC_FAIL&&errnum<=ERR_INVALID_CHAR)?
って意味あるの?
>>853
変な値を渡してきた方がわるいとは思うけど、元がNULLを返すようになっているから。

> msglist を static にしなければならないのが痛いな…
なぜ?
別にstaticにする必要はないけど。ただ不変だからstaticをつけた。
855● ◆65BWNgLL2E :03/09/21 14:16
>>851
snprintfはstrncpyでもよかったですね。

あと、配列を使うと順番や対応メッセージが間違っていないか
チェックするのが面倒くさそうなので、switchにしていました。
配列を使ったほうがずっとシンプルではありますね。
>>851
> errmsg_num_listで変換指定子がひとつもないのにsnprintfを使っているのはなぜ?
strncpy の '\0' の扱いが微妙だから,というのを推測してみる
strncat 使え,と言われたら終わりだが…

または printf だけ使おう,という姿勢なのかもしれない
フォーマット解析に掛かる時間的空間的資源が…というほどのものでもないしな


> もしも呼び出し側で書き換えることがあるのなら、呼び出し側が用意したバッファに書き込むようにするのが良いと思う。
これは同意
各所で malloc しているとソース追うのが大変
>>854
const 変数は static 付けなくても勝手に static 扱いになるんだっけ?
そうでないと errmsg_num_list 関数抜けた瞬間に msglist の内容が消えるだろ
>>857
おいおい。
autoの場合、msglistというポインタ配列は消えるが、その要素が指していたものは文字列リテラルだから消えないぞ。
staticつけたのはその配列を呼び出しのたびに作るのは無駄だと思ったから。
>>858
> その要素が指していたものは文字列リテラルだから消えないぞ。
そうなん?
>>859
そうなの。で、書き換えようとしてはいけない。
861● ◆65BWNgLL2E :03/09/21 14:25
>>858
>その要素が指していたものは文字列リテラルだから消えないぞ。

そうなんですか。

あれ? ということは、

char *errmsg_num_list(int errnum) {
   return "error message!";
}

としても平気ということですか?
>>858>>860
> autoの場合
というのが激しく気になったので
auto でない場合を含めて詳しく説明してもらえませんか?
863● ◆65BWNgLL2E :03/09/21 14:26
>>858>>862
そもそもautoって何ですか?
864● ◆65BWNgLL2E :03/09/21 14:27
>>863と聞く前にK&R本をひもといてみると・・・

「auto記憶クラス指定子 ……260」

これかな?
865● ◆65BWNgLL2E :03/09/21 14:29
だめです。理解不能です。
>>861
そうそう。もしswitchでやるならそうしよう。

>>862
autoだろうがstaticだろうが文字列そのものは同じところにおかれる。
少なくともプログラムの実行中は常に存在する。
問題はそれを指すポインタの配列がどこにつくられるか。
autoならスタックなどに呼び出しのたびに作られる。抜ければ消える。
staticならプログラムの実行中は常に存在する。
つまり&msglist[4]はstaticならOK(型の不一致は別として)だが、autoならまずい。
>>863
自動変数ってこと。
普通はつけない。関数内ではつけなければautoだから。
868● ◆65BWNgLL2E :03/09/21 14:36
>>867
なるほど、「自動変数」=「動的な局所変数」で、
対義語は「静的な局所変数」(static)ですね。
>>863
Bの名残り
>>856
printf系に統一かなるほど。
俺も文字列の出力は大抵printfだな。統一というかCといえばprintfだから(^_^;)
>>866
> 少なくともプログラムの実行中は常に存在する。
確かに,少なくとも文字列は
テキストセグメント(セグメント云々の話はともかく)には
存在し続けるはずだよなぁ…

でも…なんか納得できないなぁ…
標準関数にstrerrorという関数があるけど、悪い仕様だなぁ。
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strerror.3.html
873● ◆65BWNgLL2E :03/09/21 14:48
>>872
こんなのがあるんだ。。strerror_rと同じように作ってみようかな。
でも、なんで悪い仕様なんですか?
874● ◆65BWNgLL2E :03/09/21 14:49
ところで、manによく「スレッドセーフ」という言葉が出てきます。
(今回のstrerror/strerror_rやstrtok/strtok_rなど。)

numlist.cは「スレッドセーフ」になってるでしょうか?

後々どんな状況で使うことになるか分からないので。。。
「スレッドセーフ」でない関数を呼ばないことと、
static変数を使わないことに気を付ければいいだけでしょうか?
>>873
書き換えてはいけないならなぜ静的バッファなんか使うんだよーと。
関数ポインタを使って状態遷移を実現したいのですが
上手い宣言の書き方がわかりません。
typedefを使えば出来るそうなのですが、どのように書けば良いのでしょうか。
>>871
実行時の話をC的にこうかくと納得できるかい?

addr:0x10 {NULL, NULL, 0x100, 0x200}
addr:0x100 "memory allocation failed!"
addr:0x200 "invalid character!"

const char *msglist[4];
memcpy(msglist, 0x10, sizeof(msglist));

staticなら,&msgstrが不変,memcpyの初期化も一度きり。
autoだと,&msgstrが呼び出し毎に変化,
呼び出し毎にmemcpyで0x10から配列の内容がコピーされる。

これらと関係なく,0x100や0x200の文字列はいつでも呼び出しOK。
>>874
2つの文字列を同時にパースしてみそ、strtok使って。
たぶん困ると思うが、それが「スレッドセーフではない」問題の例だ。
>>877
> addr:0x100 "memory allocation failed!"
> addr:0x200 "invalid character!"
これらがロードされたプログラム中(=テキストセグメント)に常に存在することは分かります
が,文字列定数はこのように特別扱いされるものなのでしょうか
まあ,実際に実行してみれば納得するのでしょうが…
>>837
次のように段階的に処理すると簡単になるかも

1.与えたリスト文字列を扱いやすい形式に変換
2.扱いやすい形式から整数配列の必要要素数を取得,整数配列確保.
3.扱いやすい形式から整数配列へ整数の書き出し

ここで,扱いやすい形式というのは,「範囲」構造体の配列(と配列要素数).
"1-3,30,5-3" → { {1,3}, {30,30}, {5,3} }
のように変換してしまえば,整数配列に必要な要素数の計算も簡単,整数の書き出しも簡単.
(30 のような単項は 30-30 のような範囲として扱う)

parse_num_single() は 1 や 3 や 30 のような整数を返すことに専念.
parse_num_section() は {1,3} や {30,30} のような「範囲」を返すことに専念.
parse_num_list() は { {1,3}, {30,30}, {5,3} } のような「範囲」配列を返すことに専念.

整数配列の必要要素数の取得や,整数の書き出しは
「範囲」配列を用いて行う関数を作成する.
881880:03/09/21 18:59
typedef struct {
 int begin;
 int end;
} range_t; /* 範囲型 */

range_t *range_array = malloc( sizeof(range_t) * (strlen(string) / 2 + 1) );
int range_count;

errcode = parse_num_list( string, range_array, &range_count);

みたいな感じになるかなぁ.

range_array は要素数 strlen(string) / 2 + 1 で動的確保すればいいと思う.
最悪でも,string = "1,2,3,4,5" のように,「項」の数は string の長さ / 2 + 1 だから.
>>879
別に文字列に限ったことじゃない。
ポインタと配列は違う。それだけ。

文字列を配列と勘違いしちゃ,駄目♪駄目♪

てっきり,ポインタと配列の複合で混乱してるものと勘違い。

>>882
いや,const int型ローカル変数へのポインタを返しても同様になるんですか?
884883:03/09/21 20:18
int *int_ptr(void)
{
 const int i = 3;
 return &i;
}
char *str_buf(void)
{
 const char s[] = "abc";
 return s;
}
char *str_ptr(void)
{
 const char *s = "def";
 return s;
}
int main(void)
{
 int *ip;
 char *sb, *sp;
 ip = int_ptr();
 sb = str_buf();
 sp = str_ptr();
 /* 関数呼び出しなど,スタックを使った処理 */
 printf("*ip = %d, sb = %s, sp = %s", *ip, sb, sp);
 return 0;
}
>>883
文字列は配列だ。
>>885
>>882は嘘?
>>885
それじゃ,char *string="aaaaaa"; は文字列のポインタというべきなのか?
言語のドキュメント書いてないから,用語の扱いが自分でもちと怪しい。

>>883
const修飾子は一切関係ない。
一番の基本はポインタの参照先が static か non-static か。

>const int型ローカル変数
は,non-staticだから,そのポインタをreturnしちゃ駄目。

>>886
配列に初期値与えると,staticな領域から,
自分自身にデータコピーしちゃうんだよぉ。
嘘いってないよ〜。
ポインタなら,staticな領域のアドレス保持するだけ。
>>● ◆65BWNgLL2E
暇だったから適当に作ってみた。
多分スレッドセーフだけど出力文字数制限無しでつ。

http://do.sakura.ne.jp/~junkroom/cgi-bin/megabbs/readres.cgi?bo=lounge&vi=1064150088&res=2
889● ◆65BWNgLL2E :03/09/21 22:37
>>888
ありがとうございます!
後でじっくり研究してみます。
890デフォルトの名無しさん:03/09/22 00:12
#include <stdio.h>

int main(void)
{
printf("%cは文字です。\n",'A');
printf("%dは整数です。\n",123);
printf("%fは少数です。\n",10.5);

return 0;
}

と書いてビルドをしたんですが
「HelloWorld.c error LNK2005: _main は既に HelloWorld.obj で定義されています。」
「HelloWorld.c fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。」
とエラーが起きてしまいます。
どこに間違いがあるのでしょうか?
>>887
>885は、「リテラル文字列は配列だ」だろう。
char *string="aaaaa"はcharへのポインタに静的な配列のアドレスを代入しているだけ。
つまり、stringの指す先がたまたま静的な領域だってだけだね。
char string[]="aaaaa"はcharの配列に静的な配列の中身をコピーしている。
つまり、stringは動的な配列。

sizeof "aaaaa"とsizeof *stringとsizeof string[]をそれぞれ表示してみるといい。
>>890
そのプログラムは間違ってない。(誤字は別としてw)

たぶん、前に作ったHello Worldプログラムが残っててそれも一緒に
リンクしようととしてるんでしょ。
何のツールを使ってるか判らんけど、どこかに「プロジェクトの新規作成」
みたいなのがあると思うから探してみ。

開発ツールの使い方はすれ違いだから、探して判らなかったら当該ツールの
スレで質問してちょ。
>>892
解決しますた!(・∀・)サンクス!!!
>>890
そのソースのファイル名と
プロジェクト内のソースのファイル名を晒せ
895894:03/09/22 01:09
新着確認せずにレスしてしまった…
ドンマイ
897890:03/09/22 02:17
もうひとつ質問させてください。

#include <stdio.h>

int main(void)
{
printf("10進数の10は%dです。\n", 10);
printf("8進数の10は%dです。\n",010);
ptintf("16進数の10は%dです\n",0x10);
printf("16進数のFは%dです。\n",0xF);

return 0;
}

と書いてビルドすると
「c:\documents and settings\袋井謙一郎\my documents\visual studio projects\vsmacros71\mymacros\helloworld.c\sample\sample1.cpp(7): error C3861: 'ptintf': 識別子は、引数依存の照合を使用しても見つかりません。」
というエラーメッセージが出てきます。
なにが原因なのでしょうか?
なんか887は「スタック領域にないものは配列とは言わない」と読める
袋井謙一郎
名前でちゃった・・・
>>900 正直だな(w
>>897 スペル間違っとるよ。 ptintf → printf
ptintf → printf
ケコーン
>>901
スペルマ違い。
>>901>>902
気づきませんでした。
ありがとうございますた。
(・∀・)プティントフ!!
907デフォルトの名無しさん:03/09/22 11:27
Cで実行中のプログラムのメモリ使用量を表示するプログラムを作りたいのですがどうすればいいですか?
タスクマネージャとかはなしで。
#define STR_1 "あいうえお"
#define STR_2 "かきくけこ"

というのがあって、
char str[] = STR_1 STR_2;
と書くと
char str[] = "あいうえお" "かきくけこ";
と展開されてコンパイルが通るんですが、
char str[] = "あいうえおかきくけこ";
というの以外はエラーになると思ってたので
意外なんですが、文法的に正しいんですか?
909デフォルトの名無しさん:03/09/22 12:29
>>908
隣接する文字列定数はひとつに結合される。
>>907
coreleft()?
>>907
1バイトづつ動的に確保して、確保が失敗したところで何バイト確保できたか調べる。そしてそれを総容量から引けば使用量が出るって寸法よ。
>>911
1バイトづつ確保しても 管理用の領域はそれ以上取られるからそれでは上手くゆかないと思うよ
それ以前に消費メモリーは動的に確保されたものだけじゃないだろ。
907も911も、バカさ加減がそっくりだ。
>>907
#include <sys/sysinfo.h>
int sysinfo(struct sysinfo *info);

…え,Windows?
916915:03/09/22 13:43
>>907
Win32APIならこの辺か?
GetProcessMemoryInfo
GlobalMemoryStatus
917デフォルトの名無しさん:03/09/22 13:57
K&Rの演習1-16の題意がよくわらかないんですが、何をしたらいいんでしょうか?
一番長い行を印字するっていう目的は忘れていいんですかね?

Revise the main routine of the longest-line program so it will correctly print
the length of arbitrary long input lines, and as much as possible of the text.
918初心者です:03/09/22 14:01
2次元配列をポインタで渡せますか?
char a[4][4],b[4][4],c[4][4];等、いっぱいあるうちのどれかを渡したいのですが。
受け側では、x[4][4]として参照したいのですが‥。
919917:03/09/22 14:15
あ、改定しろって言ってるからプログラムの目的は変わらないのか。
MAXLINEを超える字数があったとしても、
正しい行の長さと、可能な限りのテキストを表示させろってことであってますかね…?
>>918
受け側の関数を、
void test(char x[][4])
と書けばよい。他にも書き方はあるけどね。
921初心者です:03/09/22 14:22
>>920 ありがとうございます
実は受け側が割り込み処理でして、引数として渡せないんです。
何か別法は‥
>>921
グローバル変数
>>919
それで、あってる。
久しぶりに、K&Rを引っ張り出して読みふけってしまった。
くしゃみが止まらない。

>>921
割込み処理を書く初心者、ってのが想像しにくいんだが・・・
アセンブラのエキスパートでC言語は初心者、ってこと?

char *x[4];
x = a;
924デフォルトの名無しさん:03/09/22 15:45
プログラムを実行してからの実行時間をプログラムに定期的に表示させるには
どのようにしたら良いですか?
例えば for ループでひとまわりする毎にその時点での実行時間を
表示させたいのですが。
>>924
プログラムの冒頭で time_begin = time();
実行時間を表示させたいときに time_now = time();
time_now - time_begin
が経過秒
>>925
time() → time(0)
927917:03/09/22 15:54
>>923
ありがとうございます。ほこりっぽいんですか
僕のはまだピカピカです。
928デフォルトの名無しさん:03/09/22 16:17
>>923
配列名に代入することはできません。
>>928
(゚Д゚)ハァ?

>>923
char *x[4];

char (*x)[4];
>>929
char *x[4]; /* char * 4個分の配列 */
x = a;
↑配列名に代入しているじゃん。
931923:03/09/22 16:32
ごめん
char (*x)[4];
だった。

漏れも、K&R勉強し直さないといけないな。
逝ってくる。
おばかな質問なんですが

たとえば2次元配列 a[100][100];

とありまして。

main() {
char a[100][100];
test( (char **)a );

}

a( char **a ) {
a[0][0] = '1';
}

とか参照と格納方式は誤ってるでしょうか?
えらいひとおしえてください

>>932
> test( (char **)a );

> a( char **a ) {
明らかに駄目だろ
>>933

miss

test( char **a) {
a[0][0]='1';
}

の誤り。つまりメインから2次元の呼び方なのれす
すんません
>>934
int型の値を返せ。
>>934
main() {
char a[100][100];
test( a );

}

test( char a[][100] ) {
a[0][0] = '1';
}

キャストすればいいというものではない
>>935
例では1個だけなんですが、実際は中で文字型とかつかったりしてたので。。。

>>936

どもありがとうございます!
さっそく参考にしてみます。
ありがとうございます
>>937
関数の型を省略するとintを返す関数と見なされる。
>>937
おまえ、すげぇ馬鹿
それならとっくの昔に答えてやったろ。
940デフォルトの名無しさん:03/09/22 17:28
すいません。誰かCで画像のパターン認識をするソース持ってないですか?載せてもらえると有り難いです。
>>940
> 画像のパターン認識
曖昧すぎ
>>940
パターン認識の方法ぐらいかけ
そしたら次はprg中での画像の扱い方について突っ込んでやるから
>>940
宿題は自分でやってください。
すいません。
C言語を始めて1ヶ月ぐらいの者です。
学校でですが・・・。
気になったのが、構文で
if とか for とか whike は 関数ですか?
上記のやつを使うときは () ← これでくぐりますよね。
だから、関数と思いました。違うんでしょうか?
945初心者です:03/09/22 18:07
>>ALL
みなさん、ありがとうございます。試して見ます。
>>944
違う。
whikeは関数かも知れない(w
あっ 間違えてしまいました。
whike じゃなくて while でした。
whike もしこれだと自作の関数になってしまう恐れがありますね。
そうですか。わかりました。
948初心者です:03/09/22 18:31
わっ、出来た!感激です。先輩方、ありがとうです!
>>947
whike = ホワイク
  whike = ホワイク
     whike = ホワイク         whike = ホワイク
       whike = ホワイク   whike = ホワイク
           whike = ホワイク
950デフォルトの名無しさん:03/09/22 20:20
うぃけ
951デフォルトの名無しさん:03/09/22 20:24
スレ立ててこよう
952デフォルトの名無しさん:03/09/22 21:37
#include <stdio.h>
void main()
{
printf("hello");
}
というソースで
ビルドの時に
エラー E2209 a.cpp 1: インクルードファイル 'stdio.h' をオープンできない
エラー E2268 a.cpp 4: 未定義の関数 'printf' を呼び出した(関数 main() )
というエラーがでました。なぜでしょうか。また対処法を教えてください
カンでレスすると、stdio.hのあるディレクトリにパスが通ってない
環境書いてみ?
954デフォルトの名無しさん:03/09/22 21:43
どういうことですか?
次スレ
C言語なら私に聞け! Part 65
http://pc2.2ch.net/test/read.cgi/tech/1064234533/
956デフォルトの名無しさん:03/09/22 21:57
 
952はソフト開発には向いてないようですね
・・・なんか段々凄いスレになってきましたね・・・
>>952
インクルードパスが通ってないってこと。
コンパイラがstdio.hってファイルを見つけることができなかったってことだよ。
埋め立て
961ユン:03/09/23 14:10
VC++でのremoveとrenameの使い方を教えてください。
何度も試してるんですが出来ません。
文法はサイトなどでしらべてあってるはずです。
なにか使えない理由とかあるんでしょうか?
>>961
どれだけマルチすりゃ気が済むんだ?
吊ってこい
馬鹿はバットファイルでもかいてろよ
964デフォルトの名無しさん:03/09/23 14:39
>>959
では、どうすれば改善されますか?教えてください
>>964
>環境はBorland C++ ver.2.31です。

フリーのコンパイラ?
バッチファイルのことか(w
>>964
コンパイラ導入の過程をもれなくこなしたか確かめろ
968デフォルトの名無しさん:03/09/23 14:53
それがこなしてないかもしれないんです
一度Borlandを消してもう一度DLしてやりたいのですが
きちんとインストールできなかったみたいで
アンインストールできません。
だからBorlandのファイルをすべて消去しようかとおもうんです。
しかし、ファイルをけしてしまうとwindowsと共有するファイルが
あったらOSがこわれますよね
だから困ってるんです。(* ̄ロ ̄)
>>968
アンインストールできないなら
上書きでインストールも無理?
970デフォルトの名無しさん:03/09/23 14:57
このBorlandは親戚がメッセで送ってきたんです。
だから不充分な所があるかもしれないので
上書きしてみます。
割れ厨キタ━━━━━(゚∀゚)━━━━━!!!!
前橋は割れ厨
973デフォルトの名無しさん:03/09/23 16:27
いやまて。
BCBはさすがにメッセンジャでは送れんだろ
BCCならフリーだったかと。
1000!!!
>>974
もう少しだね!!
>(* ̄ロ ̄)
困っているようには見えない例。
そんなことよりきいてくれ>>1
>>977
なんだ?
スレとあんま関係ないんだけどさ、
>>979
かまわんぞ。
昨日吉野屋行ったんですよ、吉野屋。
>>981
ほほう。
そしたら、なんか人大杉で書き込めないんです。
>>983
最近の吉野屋では、にちゃんねるに書き込みできるのか。
吉野家が経営不振で松屋になってたんです
吉野屋、メニューが色々選べたらいいのになあ
>>986
いろいろ選べるぞ。
並・大盛り・特盛り・つめ・ひや・なし・だく・だくだく・ねぎだく・・・
ああ、つかれた。もうダメぽ。
http://pc.2ch.net/test/read.cgi/unix/1038175909/78-90
板は違うが、こんな感じか・・・
一つのスレが終りを告げるとき
1000キター
993
ttp://www.matsuyafoods.co.jp/
これくらいのメニューの幅はほしい。

次スレ
C言語なら私に聞け! Part 65
http://pc2.2ch.net/test/read.cgi/tech/1064234533/
やたな
コーヒー飲っと♪
1000ゲット
C言語なら俺様に聞け!
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。