简体   繁体   English

Strncmp:异常分段错误

[英]Strncmp: Unusual segmentation Fault

I'm really new to C, but I've been writing C++ for a while. 我真的是C语言的新手,但是我已经有一段时间写C ++了。 I'm writing a client sever chat program. 我正在编写一个客户端服务器聊天程序。 I need to prompt the user with a couple of different options at the beginning of the session, after they've entered a username. 输入用户名后,我需要在会话开始时用几个不同的选项提示用户。 At first I was attempting to use a getchar() function, but for one reason or another, any statements of the following pattern would not yield expected results: 最初,我尝试使用getchar()函数,但是由于某种原因,以下模式的任何语句都不会产生预期的结果:

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

If the user entered 2, it would never go to the "doSomething" area. 如果用户输入2,它将永远不会转到“ doSomething”区域。 So I tried to use fgets and strncmp instead. 因此,我尝试使用fgets和strncmp代替。 But now, I keep getting segmentation faults on strncmp. 但是现在,我在strncmp上一直遇到分段错误。 Here is the most relevant part of the code, with some commented out sections from my attempts to use getchar. 这是代码中最相关的部分,其中一些注释是我尝试使用getchar的部分。 Admittedly this is kind of messy, because I was just throwing it together as a test. 诚然,这有点混乱,因为我只是将其作为一个测试而抛出。 I thought maybe allocating extra space to the string would help prevent seg faults but of course it didn't. 我认为也许为字符串分配额外的空间将有助于防止seg错误,但当然没有。

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);
    }*/
}

You can see in the leftover comments the remains of attempts to do things such as casting a char to int with a subtract. 您可以在剩余的注释中看到尝试执行操作的剩余部分,例如使用减法将char转换为int。 This comes from stuff I've found on the internet. 这来自我在互联网上找到的东西。 I also heard on the internet that getchar leaves \\n's in the input buffer. 我还在互联网上听说getchar在输入缓冲区中保留\\ n。

So here's my entire code for the client so you can put that in context: 因此,这是我为客户提供的全部代码,因此可以将其放在上下文中:

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);
    }*/
   }

} }

x[0] is a character, but x is a char* . x[0]是一个字符,但xchar* strncmp should just take x as an argument, not x[0] . strncmp应该仅将x用作参数,而不是x[0] That is, you do not want 也就是说,你不想

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

but rather 反而

strncmp(x,"a",1)

Alternatively, if you really want to emphasize that you're starting at the first character of x , you could do either of: 另外,如果您确实想强调您是从x的第一个字符开始的,则可以执行以下任一操作:

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

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

The behavior of getchar() depends on the mode of your terminal. getchar()的行为取决于终端的模式。 Most operate in "cooked" mode which means getchar() returns after you've entered a whole line (and pressed enter). 大多数操作都在“煮熟”模式下进行,这意味着在输入整行(并按Enter键)后, getchar()将返回。 Terminals do this in order to allow line editing. 终端这样做是为了允许进行行编辑。 To make getchar() return immediately, you need to switch it into "raw" mode. 要使getchar()立即返回,您需要将其切换为“原始”模式。

Next, you should enable all compiler warnings because it would have told you what is wrong with the code above: 接下来,您应该启用所有编译器警告,因为它会告诉您上面的代码出了什么问题:

strncmp() expects char* as first parameter but you passed char . strncmp()期望将char*作为第一个参数,但您传递了char That means the code will read from arbitrary memory. 这意味着代码将从任意内存中读取。

x[0] != NULL doesn't make sense either (compare character against null pointer). x[0] != NULL也没有意义(将字符与空指针进行比较)。 To know whether fgets() didn't return anything, look at its return code. 要知道fgets()是否未返回任何内容,请查看其返回代码。

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

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

Comments for the future 对未来的评论

It is generally not helpful to remove the #include lines from the full sourcecode. 从完整的源代码中删除#include行通常通常无济于事。 If I want to go and compile your code, I now have to go burn a few minutes pulling them together. 如果我想编译您的代码,那么现在我不得不花几分钟来将它们组合在一起。 It's a waste of time. 浪费时间。

Here's the extra headers that I needed to add: 这是我需要添加的额外标题:

#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);

Now then... 接着...

So if I add those headers, and I try to compile your code, I get some seriously scary warnings. 因此,如果添加这些标头,并尝试编译您的代码,则会收到一些严重的可怕警告。 Let's look at the first class of warnings. 让我们看一看警告。

This class is where you are passing variables to functions that are looking for a different type of variable. 在此类中,您可以将变量传递给正在寻找其他类型变量的函数。

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);
                             ^

The second class is where you use uninitialized variables: 第二类是使用未初始化变量的位置:

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

You should really try to fix these, because your code is broken otherwise. 您应该真正尝试解决这些问题,因为否则代码将被破坏。 If you don't understand why a particular warning is firing, then you should ask about that. 如果您不明白为什么会发出特定警告,则应对此进行询问。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM