0

私は C の初心者ですが、しばらく C++ を書いてきました。クライアントサーバーのチャットプログラムを書いています。ユーザー名を入力した後、セッションの開始時にいくつかの異なるオプションをユーザーに表示する必要があります。最初は getchar() 関数を使用しようとしていましたが、何らかの理由で、次のパターンのステートメントでは期待どおりの結果が得られませんでした。

int x = getchar();
if (x == '2') doSomething();

ユーザーが 2 を入力した場合、「doSomething」エリアには移動しません。そこで、代わりに fgets と strncmp を使用しようとしました。しかし今、strncmp でセグメンテーション違反が発生し続けています。これは、コードの最も関連性の高い部分です。getchar を使用しようとしたときにコメント アウトされたセクションがいくつかあります。確かに、これはちょっと面倒です。テストとしてまとめただけなので。文字列に余分なスペースを割り当てると、セグフォルトを防ぐのに役立つのではないかと思いましたが、もちろんそうではありませんでした。

for( ; ; )
{
  printf("\r\n1.List Users \r\n2.Chat \r\n3.Exit \r\n \r\n \r\n");

  char *x = malloc(5);

  fgets(x, 2, stdin);

  if (x[0] != NULL)
    {

      if (strncmp (x[0],"a",1) == 0)
        {
          printf("yay");
        }
    }


/* int x = getchar();
  if(x == 'a') // Compare input to 'q' character
    break;
  fprintf(stdout, "%d\n", x);*/

  /*x = c - '0';

  if (x == 1)
    getUsers(sockfd);

  if ( x == 2 )
    {

      pthread_create(&sndThread, NULL, do_send, (void *) sockfd);
      pthread_create(&rcvThread, NULL, do_recv, (void *) sockfd);

      pthread_join(sndThread, NULL);
      pthread_join(rcvThread, NULL);
    }

  if ( x == 3 )
    {
    close(sockfd);
    exit(0);
    }*/
}

残りのコメントで、減算を使用して char を int にキャストするなどの試みの跡を見ることができます。これは私がインターネットで見つけたものから来ています。getchar が入力バッファに \n を残すということもインターネットで聞きました。

したがって、これがクライアントのコード全体です。コンテキストに入れることができます。

int main(int argc, char **argv)
{
  int sockfd, i;

  char *myName = malloc(MSGSIZE);

  char c;

struct sockaddr_in servaddr;

int status;

pthread_t sndThread;
pthread_t rcvThread;

if(argc != 2)
  {
    printf("Error: expected IP address argument");
    exit(1);
}
  if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{

  error("Socket error");
}

 memset(&servaddr, 0, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORTNUM);

if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <=0)
{
  printf("inet_pton error for %s \n", argv[1]);
  exit(3);
}

if(connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
{
  error("Connect error");
}

printf("Type in a username: \r\n");

while ( fgets(myName[i],MSGSIZE,stdin ) == NULL){}


printf(">%s<\n",myName);

send_userName(myName,sockfd);

for( ; ; )
{
  printf("\r\n1.List Users \r\n2.Chat \r\n3.Exit \r\n \r\n \r\n");

  char *x = malloc(5);

  fgets(x, 2, stdin);

  if (x[0] != NULL)
    {

      if (strncmp (x[0],"a",1) == 0)
        {
          printf("yay");
        }
    }


/* int x = getchar();
  if(x == 'a') // Compare input to 'q' character
    break;
  fprintf(stdout, "%d\n", x);*/

  /*x = c - '0';

  if (x == 1)
    getUsers(sockfd);

  if ( x == 2 )
    {

      pthread_create(&sndThread, NULL, do_send, (void *) sockfd);
      pthread_create(&rcvThread, NULL, do_recv, (void *) sockfd);

      pthread_join(sndThread, NULL);
      pthread_join(rcvThread, NULL);
    }

  if ( x == 3 )
    {
    close(sockfd);
    exit(0);
    }*/
   }

}

4

3 に答える 3

2

x[0]は文字ですxが、char*です。 ではなく、単に引数としてstrncmp取る必要があります。つまり、あなたはしたくないxx[0]

strncmp(x[0],"a",1)

むしろ

strncmp(x,"a",1)

または、 の最初の文字から開始していることを本当に強調したい場合は、次のxいずれかを行うことができます。

strncmp(x+0,"a",1)

strncmp(&x[0],"a",1)
于 2014-10-09T15:24:00.803 に答える
0

今後のコメント

#include通常、完全なソースコードから行を削除することは役に立ちません。あなたのコードをコンパイルしたい場合は、それらをまとめるのに数分かかります。時間の無駄です。

追加する必要がある追加のヘッダーは次のとおりです。

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MSGSIZE 100
#define PORTNUM 12

#define SA struct sockaddr

void error(const char *);
void send_userName(const char *, int);

さて...

したがって、これらのヘッダーを追加してコードをコンパイルしようとすると、非常に恐ろしい警告が表示されます。最初のクラスの警告を見てみましょう。

このクラスは、異なるタイプの変数を探す関数に変数を渡す場所です。

foo.c:59:19: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'char *'; take the address with & [-Wint-conversion]
    while ( fgets(myName[i],MSGSIZE,stdin ) == NULL){}
                  ^~~~~~~~~
                  &
/usr/include/stdio.h:236:30: note: passing argument to parameter here
char    *fgets(char * __restrict, int, FILE *);
                                ^
foo.c:74:18: warning: comparison between pointer and integer ('int' and 'void *')
        if (x[0] != NULL)
            ~~~~ ^  ~~~~
foo.c:77:26: warning: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'; take the address with & [-Wint-conversion]
            if (strncmp (x[0],"a",1) == 0)
                         ^~~~
                         &
/usr/include/string.h:84:26: note: passing argument to parameter here
int      strncmp(const char *, const char *, size_t);
                             ^

2 番目のクラスは、初期化されていない変数を使用する場所です。

foo.c:59:26: warning: variable 'i' is uninitialized when used here [-Wuninitialized]
    while ( fgets(myName[i],MSGSIZE,stdin ) == NULL){}
                         ^
foo.c:18:18: note: initialize the variable 'i' to silence this warning
    int sockfd, i;
                 ^
                  = 0

そうしないとコードが壊れているため、これらを修正するように努める必要があります。特定の警告が発生する理由がわからない場合は、それについて質問する必要があります。

于 2014-10-09T15:32:23.157 に答える
0

の動作はgetchar()、端末のモードによって異なります。ほとんどの場合、「cooked」モードで動作しgetchar()ます。これは、行全体を入力した (Enter キーを押した) 後に戻ることを意味します。端末は、行の編集を可能にするためにこれを行います。すぐにgetchar()戻すには、「raw」モードに切り替える必要があります。

次に、すべてのコンパイラ警告を有効にする必要があります。これは、上記のコードの問題点を示しているためです。

strncmp()char*は最初のパラメータとして期待されますが、渡されcharました。これは、コードが任意のメモリから読み取ることを意味します。

x[0] != NULLどちらも意味がありません(文字とヌルポインタを比較してください)。fgets()何も返さなかったかどうかを知るには、そのリターン コードを調べます。

char * success = fgets(x, 2, stdin);
if(success == null) { ... error handling... }

if (strncmp (x,"a",1) == 0) {
    printf("yay");
}
于 2014-10-09T15:26:16.423 に答える