strcat的抛出分段故障简单残培般的密码输入

问题描述:

我使用Linux和有它的返回像getch()当前关键排序的ASCII int的自定义功能。当试图去适应它,以及如何储存我来到了一个问题,密码,我的代码如下:strcat的抛出分段故障简单残培般的密码输入

int main() { 
    int c; 
    char pass[20] = ""; 

    printf("Enter password: "); 
    while(c != (int)'\n') { 
     c = mygetch(); 
     strcat(pass, (char)c); 
     printf("*"); 
    } 

    printf("\nPass: %s\n", pass); 

    return 0; 
} 

不幸的是,我从GCC得到警告:

pass.c:26: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast 
/usr/include/string.h:136: note: expected ‘const char * __restrict__’ but argument is of type ‘char’ 

我试着使用指针,而不是一个字符数组传递,但第二个我键入一个字母它segfaults。该函数在其自身中工作,但不在循环中,至少不像getch()在Windows系统上那样。

您能看到什么与我的例子有关吗?我很享受这一点。

编辑:感谢我想出了下面的代码愚蠢的答案:

int c; 
int i = 0; 
char pass[PASS_SIZE] = ""; 

printf("Enter password: "); 
while(c != LINEFEED && strlen(pass) != (PASS_SIZE - 1)) { 
    c = mygetch(); 
    if(c == BACKSPACE) { 
     //ensure cannot backspace past prompt 
     if(i != 0) { 
      //simulate backspace by replacing with space 
      printf("\b \b"); 
      //get rid of last character 
      pass[i-1] = 0; i--; 
     } 
    } else { 
     //passed a character 
     pass[i] = (char)c; i++; 
     printf("*"); 
    } 
} 
pass[i] = '\0'; 
printf("\nPass: %s\n", pass); 
+0

+1“我正在享受这个学习。” – 2010-11-04 04:19:01

的问题是,strcat需要一个char *作为第二个参数(它连接两个字符串)。你没有两个字符串,你有一个字符串和一个char

如果你想添加cpass结束,只是不停地存储的pass当前大小的int i,然后像做

pass[i] = (char) c

确保空字符结束pass当您完成(通过设置最后一个位置为0)。

+0

完美,似乎有点愚蠢,但它的作品。我只需要添加我自己的尺寸检查,它应该很好。 – John 2010-11-04 04:23:41

单个字符与包含单个字符的字符串不同。

换句话说,'a'和'a'是非常不同的东西。

C中的字符串是以空字符结尾的字符数组。你的“通行证”是20个字符的数组 - 一个包含20个字符空间的存储器块。

函数mygetch()返回一个字符。

你需要做的是将c插入到其中一个空格中。

而不是“strcat(pass,c)”,你想做“pass [i] = c”,我从零开始,每调用一次mygetch()就增加一次。

然后,当循环完成时,您需要执行一次pass [i] ='\ 0',我等于您调用mygetch()的次数,以添加空终止符。

你另一个问题是,你没有设置针对c的值,你第一次检查,看它是否是“\ n”。您要拨打mygetch()你做比较之前:

int i = 0; 
for (;;) 
{ 
    c = mygetch(); 
    if (c == '\n') 
     break; 

    c = mygetch(); 
    pass[i++] = c; 
} 
pass[i] = '\0'; 
+0

我曾声明mygetch在开始时返回一个整数。另外,为什么使用空的for循环,如果编译器将它优化为和while/do-while循环一样清晰的东西?这似乎混乱的海事组织。 – John 2010-11-04 07:15:41

+0

你是否认为你不能将一个int分配给一个char,而不是将它转换成char? C的隐式转换将为您处理。至于使用“for(;;)”而不是“while(1)”,它们是等价的。前者自C以来就是惯用的,但你可以使用任何你感觉更舒适的方式。重要的一点是确保在测试之前初始化变量。 – 2010-11-04 13:34:09

除了以上提到的正确诊断问题与strcat()采取两个字符串 - 为什么你忽略编译器的警告,或者如果没有警告,为什么你没有打开警告吗?正如我所说的,除了这个问题之外,你还需要考虑如果你得到EOF会发生什么,而且你还需要担心'c'的初始值(虽然它可能不是'\ n' “T)。

这导致这样的代码:

int c; 
char pass[20] = ""; 
char *end = pass + sizeof(pass) - 1; 
char *dst = pass; 

while ((c = getchar()) != EOF && c != '\n' && dst < end) 
    *dst++ = c; 
*dst = '\0'; // Ensure null termination 

我从“mygetch()”切换到“的getchar()” - 主要是因为我说的话适用于并可能不适用于你的“mygetch( )'功能;我们没有关于EOF上的功能的规范。

另外,如果必须使用strcat(),你仍然需要保持在轨道上的字符串的长度,但你可以这样做:

char c[2] = ""; 
char pass[20] = ""; 
char *end = pass + sizeof(pass) - 1; 
char *dst = pass; 

while (c[0] != '\n' && dst < end) 
{ 
    c[0] = mygetch(); 
    strcat(dst, c); 
    dst++; 
} 

并不像所有的优雅 - 在上下文中使用strcat()是矫枉过正。我想,你可以做简单的计数并重复使用strcat(pass, c),但它具有二次行为,因为strcat()必须跳过后续迭代中的0,1,2,3 ......字符。相比之下,dst指向字符串末尾的NUL的解决方案意味着strcat()不必跳过任何内容。不过,在固定大小的情况下增加1个字符,你可能会更好地使用第一个循环。

+0

mygetch使用getchar,它唯一的作用是在Linux中关闭行缓冲,以便它可以逐个字符地接受字符(如conio的getch函数)。我真的很喜欢那个代码块的外观,我现在工作的代码使用char数组上的i/i ++来分配和遍历它。感谢您的洞察力。 – John 2010-11-04 07:19:46