質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

2回答

1739閲覧

C言語 文字列配列の初期化

tedmosby

総合スコア46

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

1クリップ

投稿2020/08/17 07:39

現在、C言語でソケットライブラリやselectシステムコールを用いて複数人チャットのシステムを作っています。

チャットに参加するクライアントは以下のような構造体で管理しており、ソケットディスクリプタ・名前・チャットに送信するメッセージを保存しています。

c

1typedef struct{ 2 int sock; 3 char name[NAMELENGTH]; 4 char msg[MESSAGEMAXLENGTH]; 5} client_info; 6

そして以下のようにsendシステムコールやrecvシステムコール(自作ラッパー関数を使っています)を用いて、メッセージの送受信を行っています。

c

1// チャットサーバのメインループ 2void chat_loop() 3{ 4 int msg_sender_client; // メッセージを送信したclient_idを保存する 5 int client_id; 6 static char msgprompt[]="Input your message ↓: \n"; 7 8 9 for(;;){ 10 for(client_id=0; client_id<N_client; client_id++){ 11 Send(Client[client_id].sock, msgprompt, strlen(msgprompt), 0); 12 } 13 // メッセージを送信したclient_id受け取る 14 msg_sender_client = receive_message(); 15 16 // 送信されたメッセージとユーザ名を表示 17 send_message(msg_sender_client); 18 } 19} 20 21// クライアントからのメッセージを受信して、そのclient_idを返す 22static int receive_message() 23{ 24 fd_set mask, readfds; 25 int client_id, val; 26 int strsize; 27 28 /* ビットマスクの準備 */ 29 // クライアントのソケット番号 Client[client_id].sock を監視するように設定 30 FD_ZERO(&mask); 31 for(client_id=0; client_id<N_client; client_id++){ 32 FD_SET(Client[client_id].sock, &mask); 33 } 34 35 /* 受信データの有無をチェック */ 36 readfds = mask; 37 38 // データを送ってきたクライアントを知らべる 39 select( Max_sd+1, &readfds, NULL, NULL, NULL ); 40 41 for( client_id=0; client_id<N_client; client_id++ ){ 42 if( FD_ISSET(Client[client_id].sock, &readfds) ){ 43 // ユーザのメッセージをBufで受け取る 44 strsize = Recv(Client[client_id].sock , Buf, BUFLEN-1,0); 45 Buf[strsize]='\0'; 46 47 // Bufで受信したメッセージをユーザ構造体に保存する 48 if(strsize <= MESSAGEMAXLENGTH){ 49 strncpy(Client[client_id].msg, Buf, strsize); 50 }else{ 51 strncpy(Client[client_id].msg, Buf, MESSAGEMAXLENGTH); 52 } 53 val = client_id; 54 break; 55 } 56 } 57 return val; 58} 59 60// あるクライアントから送信されたメッセージをクライアント全員に送信する 61static void send_message( int msg_sender_client ) 62{ 63 int client_id; 64 char *msg = chop_nl(Client[msg_sender_client].msg); 65 int len; 66 67 // ユーザごとにメッセージの色を変える 68 switch (msg_sender_client) { 69 case 0: 70 len = snprintf(Buf, BUFLEN, "\x1b[34m <message from Mr.%s> %s \033[m\n", 71 Client[msg_sender_client].name, msg); 72 break; 73 case 1: 74 len = snprintf(Buf, BUFLEN, "\x1b[35m <message from Mr.%s> %s \033[m\x1b[0m\n", 75 Client[msg_sender_client].name, msg); 76 break; 77 case 2: 78 len = snprintf(Buf, BUFLEN, "\x1b[36m <message from Mr.%s> %s \033[m\x1b[0m\n", 79 Client[msg_sender_client].name, msg); 80 break; 81 default: 82 len = snprintf(Buf, BUFLEN, "\x1b[36m <message from Mr.%s> %s \033[m\x1b[0m\n", 83 Client[msg_sender_client].name, msg); 84 break; 85 } 86 87 // メッセージを送信 88 for(client_id=0; client_id<N_client; client_id++){ 89 Send(Client[client_id].sock, Buf, len,0); 90 } 91 92 // 今回以前のユーザ構造体のメッセージは初期化しておく 93 // TODO:初期化できてないみたい 94 memset(Client[msg_sender_client].msg, '\0', sizeof(Client[msg_sender_client].msg)); 95// Client[msg_sender_client].msg = ""; 96} 97 98// 文字列の改行を取り除く 99static char *chop_nl(char *s) 100{ 101 int len; 102 len = strlen(s); 103 if( s[len-1] == '\n' ){ 104 s[len-1] = '\0'; 105 } 106 return(s); 107} 108 109

static void send_message( int msg_sender_client )内でメッセージの送信を行った後は、 memset(Client[msg_sender_client].msg, '\0', sizeof(Client[msg_sender_client].msg));としてユーザのメッセージを初期化しているのですが、どうやらそれがうまく行っておらず、実行時に長めのメッセージの送信を行うとその後にそのメッセージのキャッシュ??が残ってしまいます。

長めのメッセージを送信した時

どうすればメッセージを初期化することができるのかわからないため、教えていただきたいです。
よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SHOMI

2020/08/17 08:09

sendで送った内容が一度のrecvですべて受信されるとは限りません。 分割されて受信されたのではありませんか? 送った長めのメッセージと、一度目に受信されたメッセージの文字数はあっていますか?
SHOMI

2020/08/17 08:10

一度目と二度目でmsg_sender_clientの値は同じなのでしょうか。
tedmosby

2020/08/17 08:49

一度目と二度目で同じユーザ(同じmsg_sender_client)で、長いメッセージを送信した後ほかのユーザでメッセージを送信すると上記のようにはならず、キーボード入力した内容のみが送信されます。 メッセージの長さは#define MESSAGEMAXLENGTH 140として決定していて、static int receive_message()内でその長さまでのメッセージならそのまま受信して、それより長いメッセージならMESSAGEMAXLENGTHまで受信するようにしています。 // Bufで受信したメッセージをユーザ構造体に保存する if(strsize <= MESSAGEMAXLENGTH){ strncpy(Client[client_id].msg, Buf, strsize); }else{ strncpy(Client[client_id].msg, Buf, MESSAGEMAXLENGTH); } val = client_id; break;
tedmosby

2020/08/17 08:50

メッセージの送信では、static void send_message( int msg_sender_client )内で、 // メッセージを送信 for(client_id=0; client_id<N_client; client_id++){ Send(Client[client_id].sock, Buf, len,0); } としています。 BUFは #define BUFLEN 500 /* 通信バッファサイズ */ static char Buf[BUFLEN]; /* 通信用バッファ */ となっています。 BUFLENとMESSAGEMAXLENGTHが異なることが問題なのでしょうか??
SHOMI

2020/08/17 08:59 編集

受信長がMESSAGEMAXLENGTH以上の場合msgに終端の'\0'が付きませんよ。 それだけが問題かはわかりませんが。
guest

回答2

0

既にコメントが付いているみたいですが、、、

char msg[MESSAGEMAXLENGTH];

に対し、

strncpy(Client[client_id].msg, Buf, MESSAGEMAXLENGTH);

は、文字列の最後に '\0'が付かないので、ダメです。(もう一つも strsize = MESSAGEMAXLENGTH の時、同様にダメ)
char msg[MESSAGEMAXLENGTH + 1]; のようにして、msg[MESSAGEMAXLENGTH] ='\0' としましょう。 strncpy()は、'\0'を付けない時があります。

投稿2020/08/17 12:22

pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Clientという配列が定義されていないようですが、そこらへんはどうなってるんでしょうか。

投稿2020/08/17 08:05

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tedmosby

2020/08/17 08:42

省略させていただきましたが、static client_info *Client; /* クライアントの情報 */ で定義しています。
y_waiwai

2020/08/17 08:44

肝心なところを省略されてはどもなりませんねー
y_waiwai

2020/08/17 08:50

Clientがどういう初期化されてるのか不明ですが、msg_sender_clientがClientの範囲内である、というのをしっかり確認しよーね。 #おそらく範囲外アクセスでおかしくなってるものとえすぱー
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問