マルチバイトの変換後出力がaが追加される

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ぷぷぷジューシー
記事: 28
登録日時: 3年前
住所: アンドロメダ銀河系のどこかに住んでいる

マルチバイトの変換後出力がaが追加される

#1

投稿記事 by ぷぷぷジューシー » 3年前

何故aが追加されるか分かりません

コード:

#include <stdio.h>
#include <uchar.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char32_t in[] = U"http://google.com"; // or "z\u00df\u6c34\U0001F34C"
    mbstate_t mbstate = {0};
    char rpath[MB_LEN_MAX+5];
    char* as;
 
    if (in[0] =='/'){
      printf("\n/を発見した\n");
    }

    size_t bmfunc_rlen = c32rtomb(rpath ,in[0], &mbstate);
      if ((size_t)(-1) == bmfunc_rlen){
        printf("エラーが発生しました\n");
        printf("有効なワイド文字ではありません\n");
        printf("エラー size_t サイズ : %zu\n", bmfunc_rlen);
        return 0;
      }
      printf(" ここだよ %s\n", rpath);
      strcat(as, rpath);
      printf("結合後: %s\n", as);
}
面倒なことはCGo使おう!

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: マルチバイトの変換後出力がaが追加される

#2

投稿記事 by みけCAT » 3年前

c32rtomb | Programming Place Plus C言語編 標準ライブラリのリファレンス
注意
あくまで文字の変換なので、末尾に終端文字(U'\0') は付加されない。
文字列ではないもの(ナル終端されていない文字配列)を文字列を要求するstrcatに渡しているため、
不定である未初期化の自動変数の値の参照が発生し、未定義動作になります。
さらに、asも未初期化のままstrcatに渡されているため、未定義動作になります。

コード:

printf(" ここだよ %s\n", rpath);
の前に

コード:

as = calloc(MB_LEN_MAX+5, sizeof(*as));
if (as == NULL) {
  perror("calloc");
  return 1;
}
rpath[bmfunc_rlen] = '\0';
を加えると改善するでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ぷぷぷジューシー
記事: 28
登録日時: 3年前
住所: アンドロメダ銀河系のどこかに住んでいる

Re: マルチバイトの変換後出力がaが追加される

#3

投稿記事 by ぷぷぷジューシー » 3年前

みけCAT さんが書きました:
3年前
c32rtomb | Programming Place Plus C言語編 標準ライブラリのリファレンス
注意
あくまで文字の変換なので、末尾に終端文字(U'\0') は付加されない。
まさかそんなことだったとは地味に悔しいですq

一応、動いてくれましたc言語に詳しくないのでバグがまだありそうですが
asを初期化しないでwindowsのコマンドプロンプトから実行するとなぜか上手いこといかないのでasを初期化しました。windowsのPowerShellでは上手いこといくのに

コード:

#include <stdio.h>
#include <uchar.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char32_t in[] = U"ttp://google.com"; // or "z\u00df\u6c34\U0001F34C"
    mbstate_t mbstate = {0};
    char rpath[MB_LEN_MAX+1];
    char* as = '\0';
 
    if (in[0] =='/'){
      printf("\n/を発見した\n");
    }

    size_t bmfunc_rlen = c32rtomb(rpath ,in[0], &mbstate);
    if ((size_t)(-1) == bmfunc_rlen){
      printf("エラーが発生しました\n");
      printf("有効なワイド文字ではありません\n");
      printf("エラー size_t サイズ : %zu\n", bmfunc_rlen);
      return 0;
    }

    rpath[(size_t)strlen(rpath)] = '\0';
    
    printf(" ここだよ %s\n", rpath);
    printf("a%#x\n", as);
    printf("c%#x\n", rpath);
    as = malloc((size_t)sizeof(rpath));
    strcat(as, rpath);
      printf("結合後: %s\n", as);
      printf("b%#x", as);
      free(as);

}
面倒なことはCGo使おう!

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: マルチバイトの変換後出力がaが追加される

#4

投稿記事 by みけCAT » 3年前

大量に未定義動作をしていますね。
また、定義があるlimits.hをincludeせずにMB_LEN_MAXを使っているという問題もあります。

コード:

#include <stdio.h>
#include <uchar.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
    char32_t in[] = U"ttp://google.com"; // or "z\u00df\u6c34\U0001F34C"
    mbstate_t mbstate = {0};
    char rpath[MB_LEN_MAX+1];
    char* as = '\0';
 
    if (in[0] =='/'){
      printf("\n/を発見した\n");
    }

    size_t bmfunc_rlen = c32rtomb(rpath ,in[0], &mbstate);
    if ((size_t)(-1) == bmfunc_rlen){
      printf("エラーが発生しました\n");
      printf("有効なワイド文字ではありません\n");
      printf("エラー size_t サイズ : %zu\n", bmfunc_rlen);
      return 0;
    }

    /*
    未定義動作:初期化されていない自動変数の値の使用
    strlenは文字列(ナル終端された文字の列)を要求するのに、
    ナル終端されていない配列が渡されている。
    また、もし初期化されていたとしても、
    strlen(rpath)にはもともと'\0'が入っているはずなので、意味のないコードである。
    '\0'を書き込む位置はbmfunc_rlenを用いて決めるべき。
    */
    rpath[(size_t)strlen(rpath)] = '\0';
    
    printf(" ここだよ %s\n", rpath);
    /*
    未定義動作:書式とデータのミスマッチ
    %xはunsigned int型のデータを要求するが、asはchar*型である。
    printfを用いてポインタを出力するには、
    出力するポインタをvoid*型にキャストし、書式%pを用いるべきである。
    */
    printf("a%#x\n", as);
    /*
    未定義動作:書式とデータのミスマッチ
    %xはunsigned int型のデータを要求するが、rpathはchar*型に変換されて渡される。
    printfを用いてポインタを出力するには、
    出力するポインタをvoid*型にキャストし、書式%pを用いるべきである。
    */
    printf("c%#x\n", rpath);
    as = malloc((size_t)sizeof(rpath));
    /*
    未定義動作:mallocで確保され、初期化されていない領域の値の使用
    strcatは文字列(ナル終端された文字の列)を要求するのに、
    ナル終端されていない配列が渡されている。
    rpathにはきちんと文字列を格納するように修正することを前提として、
    この場合、strcatではなくstrcpyを用いるのがよいだろう。
    */
    strcat(as, rpath);
      printf("結合後: %s\n", as);
      /*
      未定義動作:書式とデータのミスマッチ
      %xはunsigned int型のデータを要求するが、asはchar*型である。
      printfを用いてポインタを出力するには、
      出力するポインタをvoid*型にキャストし、書式%pを用いるべきである。
      */
      printf("b%#x", as);
      free(as);

}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ぷぷぷジューシー
記事: 28
登録日時: 3年前
住所: アンドロメダ銀河系のどこかに住んでいる

Re: マルチバイトの変換後出力がaが追加される

#5

投稿記事 by ぷぷぷジューシー » 3年前

みけCAT さんが書きました:
3年前
大量に未定義動作をしていますね。
コンパラ君...

'\0'君も確認できたし大丈夫だろう

コード:

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <uchar.h>
#include <limits.h>
#include <stdlib.h>


int geturlparserfunc(const char*,   char*, char*);

int main(void)
{
  char hostname, pathname;
  geturlparserfunc("https://youtube.com", &hostname, &pathname);

  printf("ホスト名; %s\n", hostname);
  printf("パッチ名: %s\n", pathname);

}

int geturlparserfunc(const char* name,   char* rhost, char* rpath)
{
  size_t bmfunc_rlen;
  int  inputlen = strlen(name) + 1;
  char input[(int)inputlen];
  char32_t inp32b[(int)inputlen + 1];
  int arraycount1 = 0, arraycount2 = 0;
  mbstate_t mbstate = 0;
  char temphost[MB_LEN_MAX+5];
  char temppath[MB_LEN_MAX+5];

  int slashconunt = 0, colon = 0;


  strcpy_s(input, inputlen, (char*)(name));

  while (1){
    bmfunc_rlen = mbrtoc32(&inp32b[arraycount1], &input[arraycount2], MB_LEN_MAX, &mbstate);
    if ( (size_t)(-1) == bmfunc_rlen ){
      printf("エラーが発生しました\n");
      printf("エンコードエラー又はバイト数が足りませんの可能性があります。");
      printf("エラー size_t サイズ : %zu\n", bmfunc_rlen);
      break;
    } else if ( (size_t)(-2) == bmfunc_rlen ){
      printf("エラーが発生しました\n");
      printf("マルチバイト文字の可能性があります。");
      printf("エラー size_t サイズ : %zu\n", bmfunc_rlen);
      break;
    } else if ( (size_t)(-3) == bmfunc_rlen ){
      arraycount1++;
      continue;
    }  else if (( (size_t)(0) == bmfunc_rlen ) ){
      break;
    } else if ( (size_t)(0) < bmfunc_rlen ){
    	arraycount1++;
      arraycount2 += (int)(bmfunc_rlen);
    } 
  }

  for (size_t n = 0; arraycount1 > n ; n++){
    printf("%#x\n", inp32b[n]);
    if (inp32b[n] == ':' || inp32b[n] == '/'){
      if (inp32b[n] == ':'){
        colon = 1;
      }
      if (inp32b[n] == '/'){
        slashconunt+=1;
      }
    }
    if (slashconunt > 3 && colon == 1) {
      bmfunc_rlen = c32rtomb(rpath ,inp32b[n], &mbstate);
      if ((size_t)(-1) == bmfunc_rlen){
        printf("エラーが発生しました\n");
        printf("有効なワイド文字ではありません\n");
        printf("エラー size_t サイズ : %zu\n", bmfunc_rlen);
        break;
      }
      printf("%s\n", rpath);
    }

    if (slashconunt == 2 && colon == 1){
      // rhost 処理
      bmfunc_rlen = c32rtomb(rhost ,inp32b[n], &mbstate);
      if ((size_t)(-1) == bmfunc_rlen){
        printf("エラーが発生しました\n");
        printf("有効なワイド文字ではありません\n");
        printf("エラー size_t サイズ : %zu\n", bmfunc_rlen);
        break;
      }
    }
  }

  printf("temppath:\t %s\n", rhost);
  printf("temphost:\t %s\n", rpath);

  arraycount1 = 0, arraycount2 = 0, slashconunt = 0, colon = 0 , bmfunc_rlen = 0;

  return 0;
}

面倒なことはCGo使おう!

返信

“C言語何でも質問掲示板” へ戻る