【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.20628

コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---ひか(2005/04/16 03:31:08)


学校でコマンドライン引数からC言語で変数名として使える文字列のみを選ぶという課題が出ました。
条件として
1)最初の文字は"_"もしくは"英字"
2)2文字以降は"_"もしくは"英数字"
3)文字列の長さは31以内
4)予約語は使えない

3、4は問題なく言ったのですが1、2がうまくいきません。
作ってみたソースです。(予約語の判定の関数は抜いてあります)
Linux上で動作するCで動かしてます。
助言お願い致します。

int forallchar(const char *s0, int (*p)(int), int (*q)(int))
{
  const char *s;
  s = s0;
  //入力された文字列が一文字の場合
  if ((strncmp(s, "_", 1) == 0 || (*q)((int)*(s))) && strlen(s)==1 )
    return 1;  //_か英字なら1を返す
  //上記でない場合
  if (strncmp(s, "_", 1) ==  0 || (*q)((int)*(s))){
    //一文字目が_か英字なら次の手続き
    for (s = s0+1; *s != '\0'; s++){//sをNULL文字まで回す(文字を一個づつみる)
      if (strcmp(s, "_") ==0  || !(*p)((int)*s)){
        return 1;
        //_か英数字なら1を返す
      }
    }
    return 0;
  }
  return 0;
}

main(int argc, char *argv[])
{
  int exitstat = 0;
  int pos;
  char *str;
  for (pos = 1; pos < argc; pos ++) {
    str = argv[pos];    /*strはargv配列をさしている*/
    if (forallchar(str, isalnum, isalpha)
        && ((strlen(str)) <= 31)){
      /*文字数は31以内*/
     if(yoyakugo(str) ==1)/*予約語でない場合*/
       printf("%s\n", argv[pos]);
    } else {
      exitstat = 1;
    }
  }
    return exitstat;
}




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ 20630 しーさー 2005/04/16 09:41:31
<子記事> Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ 20632 shu 2005/04/16 10:57:09
<子記事> Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ 20635 まきじ 2005/04/16 12:11:46
<子記事> Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ 20642 RiSK 2005/04/16 16:27:04
<子記事> Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ 20643 NykR 2005/04/16 16:41:04


No.20630

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---しーさー(2005/04/16 09:41:31)


おはようございます。
しーさーです。

>1)最初の文字は"_"もしくは"英字"
>2)2文字以降は"_"もしくは"英数字"
>3)文字列の長さは31以内
>4)予約語は使えない

ソース読む気力がなかったので、作ってみました。
参考にでもしてください。
適当な動作確認しかしてないからバグがあるかも。。。(というかありそう。。)

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

int forallchar(char*);

int main(int argc, char* argv[])
{
    int i, cnt, rtn;
    char* buf;

    cnt = argc;
    if (cnt < 2) {
        printf("コマンド入力値が不正です\n");
        return(-1);
    }

    for (i = 1; i < cnt; i++) {
        buf = argv[i];
        //文字列チェック関数
        rtn = forallchar(buf);
        if (rtn == 0) {
            printf("%s\n", buf);
        }
    }

    return(0);
}

int forallchar(char* chkchar)
{
    char* buf;
    int i, len;
    buf = chkchar;

    len = strlen(buf);
    //文字列長チェック
    if (len > 31) {
        return(-1);
    }

    //1文字目チェック
    if ( (buf[0] < 0x41 || 0x5a < buf[0])
      && (buf[0] < 0x61 || 0x7a < buf[0])
      && (buf[0] != 0x5f) ) {
        return(-1);
    }

    //2文字目以降チェック
    for (i = 1; i < len; i++) {
        if ( (buf[i] < 0x30 || 0x39 < buf[i])
          && (buf[i] < 0x41 || 0x5a < buf[i])
          && (buf[i] < 0x61 || 0x7a < buf[i])
          && (buf[i] != 0x5f) ) {
            return(-1);
        }
    }

    //予約語チェックをここに入れる

    return(0);
}


>学校でコマンドライン引数からC言語で変数名として使える文字列のみを選ぶという課題が出ました。
>条件として
>1)最初の文字は"_"もしくは"英字"
>2)2文字以降は"_"もしくは"英数字"
>3)文字列の長さは31以内
>4)予約語は使えない
>
>3、4は問題なく言ったのですが1、2がうまくいきません。
>作ってみたソースです。(予約語の判定の関数は抜いてあります)
>Linux上で動作するCで動かしてます。
>助言お願い致します。
>
><pre>int forallchar(const char *s0, int (*p)(int), int (*q)(int))
{
const char *s;
s = s0;
//入力された文字列が一文字の場合
if ((strncmp(s, "_", 1) == 0 || (*q)((int)*(s))) && strlen(s)==1 )
return 1; //_か英字なら1を返す
//上記でない場合
if (strncmp(s, "_", 1) == 0 || (*q)((int)*(s))){
//一文字目が_か英字なら次の手続き
for (s = s0+1; *s != '\0'; s++){//sをNULL文字まで回す(文字を一個づつみる)
if (strcmp(s, "_") ==0 || !(*p)((int)*s)){
return 1;
//_か英数字なら1を返す
}
}
return 0;
}
return 0;
}

main(int argc, char *argv[])
{
int exitstat = 0;
int pos;
char *str;
for (pos = 1; pos < argc; pos ++) {
str = argv[pos]; /*strはargv配列をさしている*/
if (forallchar(str, isalnum, isalpha)
&& ((strlen(str)) <= 31)){
/*文字数は31以内*/
if(yoyakugo(str) ==1)/*予約語でない場合*/
printf("%s\n", argv[pos]);
} else {
exitstat = 1;
}
}
return exitstat;
}

</pre>



この投稿にコメントする

削除パスワード

No.20636

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---undefined name(2005/04/16 14:02:38)


文字コード依存。
isalpha, isalnum などを使うのが好ましい。


この投稿にコメントする

削除パスワード

No.20638

ありがとうございます!
投稿者---ひか(2005/04/16 14:29:22)


しーさー様、ソース参考にさせていただきました。
ASCII文字コードで判定できるのを忘れてました。
よくよく考えたらisalnumは英字と10進数を示すんですね。
ずっと英数字だと勘違いしていました。(^^;)
isalphaと文字コードを両方使ったらできました。
皆様、的確なご指導ありがとうございました!


この投稿にコメントする

削除パスワード

No.20632

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---shu(2005/04/16 10:57:09)


http://www9.plala.or.jp/sgwr-t/c/sec07.html#s7-2


この投稿にコメントする

削除パスワード

No.20635

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---まきじ(2005/04/16 12:11:46)


>1)最初の文字は"_"もしくは"英字"
>2)2文字以降は"_"もしくは"英数字"

作ってみました。

#include<stdio.h>

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

    char* str = *(argv+1);
    
    if(argc != 2) return(EXIT_SUCCESS);
    
    printf("判定文字列:%s\n",str);
    if((*str >= 'A' && *str <= 'Z') || 
        (*str >= 'a' && *str <= 'z') || 
            (*str == '_')){
            
        printf("1 文字目 OK\n");
        str++;
        
        while((*str >= 'A' && *str <= 'Z') || 
                (*str >= 'a' && *str <= 'z') || 
                (*str >= '0' && *str <= '9') || 
                    (*str == '_')){
            str++;
        }
        
        if(*str == '\0') printf("2 文字目以降 OK");
        else printf("2 文字目以降 NG");
        
    }else{
        printf("1 文字目 NG\n");
    }
    return(EXIT_SUCCESS);
}




この投稿にコメントする

削除パスワード

No.20637

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---undefined name(2005/04/16 14:05:57)


こちらも文字コード依存。(文字を範囲指定すると環境に依存する)
isalpha, isalnum などを使うのが好ましい。


この投稿にコメントする

削除パスワード

No.20640

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---まきじ(2005/04/16 15:21:56)


>こちらも文字コード依存。(文字を範囲指定すると環境に依存する)
>isalpha, isalnum などを使うのが好ましい。

文字コードでの範囲指定なら環境依存するのは納得がいきますが、
文字リテラルでの環境依存はよく分かりません。

printf("%d",'A');
printf("%c",65);

ASCII コードなら、'A' を 10進数(%d)として表示すると、65 とでます。
逆に、65 を文字(%c)として表示する、'A' がでます。

printf("%d",'A'); は、
どの環境でも、その環境の 'A' の文字コードが
表示されると思います。
逆に、表示された文字コードを文字として表示すれば、
'A' が表示される思います。

printf("%c",65); は
対応する文字コードが違う為、'A' でない可能性がある。
これが環境依存だと思います。

説明がうまくできませんが、言いたい事が分かって貰えれば幸いです。


この投稿にコメントする

削除パスワード

No.20641

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---RiSK(2005/04/16 16:17:36)


'A' < 'Z' である保証はありません。
だから文字コードに依存するのですよ。


この投稿にコメントする

削除パスワード

No.20642

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---RiSK(2005/04/16 16:27:04)


/*学校でコマンドライン引数からC言語で変数名として使える文字列のみを選ぶという課題が出ました。
条件として
1)最初の文字は"_"もしくは"英字"
2)2文字以降は"_"もしくは"英数字"
3)文字列の長さは31以内
4)予約語は使えない
*/
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#define IS_NON_FIGURE(c) (isalpha((c)) | ((c) == '_'))
static int IsKeyword(const char * s)
{
    static const char * keywords[] = {
        "auto",
        "break",
        "case",
        "char",
        "const",
        "continue",
        "default",
        "do",
        "double",
        "else",
        "enum",
        "extern",
        "float",
        "for",
        "goto",
        "if",
        "inline",
        "int",
        "long",
        "register",
        "restrict",
        "return",
        "short",
        "signed",
        "sizeof",
        "static",
        "struct",
        "switch",
        "typedef",
        "union",
        "unsigned",
        "void",
        "volatile",
        "while",
        "_Bool",
        "_Complex",
        "_Imaginary"
    };
    unsigned i;
    for (i = 0; i < sizeof(keywords)/sizeof(keywords[0]); ++i)
        if (strcmp(s, keywords[i]) == 0) return 1;
    return 0;
}
int IsIdentifier(const char * s)
{
    int is_id = 0;
    const char * const p = s;
    while (*s) {
        switch (is_id) {
        case 0:
            if (IS_NON_FIGURE(*s)) {
                ++s;
                is_id = 1;
            } else return 0;
            break;
        case 1:
            if (isalnum(*s)) ++s;
            else return 0;
        }
    }
    if (strlen(p) > 31) return 0;
    if (IsKeyword(p)) return 0;
    return 1;
}

int main(int argc, char ** argv)
{
    if (argc < 2) return 1;
    while (*++argv) if (IsIdentifier(*argv)) puts(*argv);
    return 0;
}



この投稿にコメントする

削除パスワード

No.20643

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---NykR(2005/04/16 16:41:04)


4は省略
#include <stdio.h>

#define NON_DIGIT "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DIGIT "0123456789"

int is_identifier(const char * s)
{
  char  str[31];
  char  dummy;
  return (sscanf(s, "%1["NON_DIGIT"]", str) == 1 &&
          sscanf(s + 1, "%30["NON_DIGIT DIGIT"]%c", str, &dummy) == 1);
}

int main(int argc, char ** argv)
{
  int   i;
  for (i = 1; i < argc; i++) {
    if (!is_identifier(argv[i]))
      continue;

    puts(argv[i]);
  }

  return 0;
}


アルファベットと数字は一々書き下さなくてもa-zのような書き方でも大丈夫だと思いますが(Linuxということはgccでしょうか? なら大丈夫)、一応処理系依存なので。


この投稿にコメントする

削除パスワード

No.20649

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---RAPT(2005/04/17 03:38:23)


> 処理系依存
確か「数字」('0'〜'9')に関しては、('0' + 1) == '1'の関係で
その連続性は保証されていたと思います。



この投稿にコメントする

削除パスワード

No.20650

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---undefined name(2005/04/17 10:30:17)


> ('0' + 1) == '1'の関係で

C言語としては環境依存にかわりないが、なぜこれを保証していると思われるか、ソースがあればご提示いただきたい。
特定処理系や特定文字コード規格の保証と混同されてはいまいか。



この投稿にコメントする

削除パスワード

No.20651

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---RiSK(2005/04/17 13:17:16)


>> ('0' + 1) == '1'の関係で
>
> C言語としては環境依存にかわりないが、なぜこれを保証していると思われるか、ソースがあればご提示いただきたい。
>特定処理系や特定文字コード規格の保証と混同されてはいまいか。
5.2.1 文字集合
ソース基本文字集合および実行基本文字集合の各要素の表現は,10進数字に関する上の並びにおいて,0の右側に並んでいる各文字の値は,一つ左側にある文字の値に比べ1だけ大きくなければならない。



この投稿にコメントする

削除パスワード

No.20652

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---RiSK(2005/04/17 13:24:39)


ごめんなさい。不完全な引用でした。
X3010 より引用です。
「10進数字に関する上の並び」について引用を追加します。
 ソース基本文字集合および実行基本文字集合は,少なくとも次に掲げる要素を持っていなければならない。 (...snip...)
−10個の10進数字(digit)
0 1 2 3 4 5 6 7 8 9
(...snip...)
(先の引用文が続く)

つまりRAPTさんの仰るとおりということです。


この投稿にコメントする

削除パスワード

No.20654

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---undefined name(2005/04/17 15:17:06)


X3010 であれば「C言語」の保証根拠としては確かに十分で、
当方の確認不足を認めざるを得ない。もうしわけない…。

但し、以下の点を留保させていただきたい。
今はCの規格書を確認できないためX3014(C++)からの類推で
申し訳ないが、X3014 の「文字集合」で、同様に
「上で掲げた表の0以降のそれぞれの数字に対応する文字の値は、
 それの直前にある文字の値より1だけ大きくなければならない」
という記述があるが、これは原文ISO14882 では単に
「the value of the members shall be non-negative and distinct
from one another.」
とあるだけで連続性の保証はないのだが、同様なことは
「Programming Language C」と「C言語」の間に存在しないのだろうか。

つまり、「C言語」としては保証されているが、国際的な
「Programming Language C」としては保証がない可能性があるのでは
ないかと思う。原文はどうなっているのだろうか。
また、識者の方のご意見などあればぜひ伺ってみたい。


この投稿にコメントする

削除パスワード

No.20655

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---YuO(2005/04/17 17:50:43)


>申し訳ないが、X3014 の「文字集合」で、同様に
>「上で掲げた表の0以降のそれぞれの数字に対応する文字の値は、
> それの直前にある文字の値より1だけ大きくなければならない」
>という記述があるが、これは原文ISO14882 では単に
>「the value of the members shall be non-negative and distinct
>from one another.」
>とあるだけで連続性の保証はないのだが、同様なことは

えーっと,ISO/IEC 14882:2003 2.2 Character setsの第3段落に

In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.


とあります。
#1998には確かにないですね……。


>「Programming Language C」と「C言語」の間に存在しないのだろうか。

ISO/IEC 9899:1999 5.2.1 Character setsの第3段落に,まったく同一の記述があります。



この投稿にコメントする

削除パスワード

No.20656

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---undefined name(2005/04/17 18:43:14)


>#1998には確かにないですね……。

…2003では追記されているわけですか。ご指摘感謝。> YuO殿

全面的に当方の情報が古い・誤りだったようで、申し訳ない。


<独り言>
…再度最新規格の入手申請をしてみよう…(以前は蹴られた…)


この投稿にコメントする

削除パスワード

No.20665

Re:コマンドライン引数からC言語の変数名に使える文字列を選ぶ
投稿者---NykR(2005/04/18 13:54:48)


>> 処理系依存

あ〜それではなくてですね、scanf ファミリの仕様で、
JIS X3010 7.19.6.2 fscanf関数

文字- (ハイフン) が走査文字の並びに含まれ, かつ先頭の文字 (先頭が文
字^のときは2文字目) でも最後の文字でもない場合の動作は, 処理系定義と
する。

となっているんです。だから操作文字の並び 0-9 がコード順に展開されて0123456789となるかどうかは処理系に依存する、ということです。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧