C 自定义获取行输入函数

C 自定义获取行输入函数,c,buffer-overflow,kernighan-and-ritchie,C,Buffer Overflow,Kernighan And Ritchie,我正在读K&R的书,有点卡住了 下面的问题是什么 void getInput(int* output) { int c, i; for(i=0; (c = getchar()) != '\n'; i++) output[i] = c; // printf("%c", c) prints the c value as expected output[++i] = '\0'; } 当我运行程序时,它永远不会退出循环,我必须按住Ctrl+C键才能退出。但是,如果我将第五行

我正在读K&R的书,有点卡住了

下面的问题是什么

void getInput(int* output) {
   int c, i;
   for(i=0; (c = getchar()) != '\n'; i++)
     output[i] = c; // printf("%c", c) prints the c value as expected
   output[++i] = '\0';
}

当我运行程序时,它永远不会退出循环,我必须按住Ctrl+C键才能退出。但是,如果我将第五行替换为
printf(“%c”,c),在按enter键并创建新行后,它会很好地打印出所有输入。

在我看来,除了不需要在循环外增加i之外,它写得很正确。i在循环退出之前增加,因此它已经在您想要的地方了

请确保“\n”实际上正在将其转换为c


有时“\n”会被当作分隔符扔掉。

这是一种冒缓冲区溢出风险的简单方法,因为输出的大小永远不会被传递/检查

下面的问题是什么

void getInput(int* output) {
   int c, i;
   for(i=0; (c = getchar()) != '\n'; i++)
     output[i] = c; // printf("%c", c) prints the c value as expected
   output[++i] = '\0';
}
为什么输入参数是int*,而您想要存储在一个字符数组中? 大概

void getInput(char* output) {
这样更好

另外,您如何知道输出指针指向您拥有足够内存以写入用户输入的某个位置?也许您必须将最大缓冲区长度作为一个额外参数,以避免缓冲区溢出错误

我已经在for循环中增加了一个额外的时间,因此您可以执行以下操作:

output[i] = '\0';
除此之外,程序运行良好,输出我们输入的内容,直到返回

FWIW,我这样称呼它来测试它:

 int main(void)
{
    char o[100];
    getInput(o);
    printf("%s", o);
    return 0;
}

这是一个完整的程序,从您的输入中进行了几次更新,但它仍然无法脱离循环。顺便说一句,这是第34页的练习1-24

#include <stdio.h>

#define STACK_SIZE 50
#define MAX_INPUT_SIZE 1000
#define FALSE 0
#define TRUE 1

void getInput();
int validInput();

int main() {
  char* userInput[MAX_INPUT_SIZE];

  getInput(&userInput);

  if (validInput(&userInput) == TRUE)
    printf("Compile complete");
  else
    printf("Error");
}

// Functions
void getInput(char* output) {
  int c, i;
  for(i=0; (c = getchar()) != '\n' && c != EOF && i <= MAX_INPUT_SIZE; i++)
    output[i] = c;
  output[i] = '\0';
}

int validInput(char* input) {
  char stack[STACK_SIZE];
  int c;
  int j;

  for (j=0; (c = input[j]) != '\0'; ) {
    switch(c){
      case '[': case '(': case '{':
        stack[j++] = c;
        break;
      case ']': case ')': case '}':
        if (c == ']' && stack[j] != '[')
          return FALSE;
        else if (c == '}' && stack[j] != '{')
          return FALSE;
        else if (c == ')' && stack[j] != '(')
          return FALSE;

        // decrement the stack's index  
        --j;
        break;
    }
  }

  return TRUE;
}
#包括
#定义堆栈大小为50
#定义最大输入大小1000
#定义FALSE 0
#定义真1
void getInput();
int validInput();
int main(){
char*userInput[MAX_INPUT_SIZE];
getInput(&userInput);
if(validInput(&userInput)==TRUE)
printf(“编译完成”);
其他的
printf(“错误”);
}
//功能
void getInput(字符*输出){
int c,i;

对于(i=0;(c=getchar())!='\n'&&c!=EOF&&i你试过使用调试器吗?你应该在gdb或visual studio或任何你正在使用的程序中逐步检查代码,看看发生了什么。你说你是初学者,所以可能你还没有考虑到这一点-这是一种非常正常的调试技术。

我可以看到你上一次发布的代码有3个错误:

char* userInput[MAX_INPUT_SIZE];
应该是:

char userInput[MAX_INPUT_SIZE+1];
getInput( userInput );
(这已经被暗黑破坏神Pax提到了)

应该是:

char userInput[MAX_INPUT_SIZE+1];
getInput( userInput );

最后一个错误意味着您在调用堆栈中向getInput传递了一个地址。您的内存被覆盖。可能您对getchar()的一个调用返回了错误的地址。

这是最后一个工作代码。我必须说,我从这一操作中获得了不少经验。感谢您的帮助和指点

对如何做得更好有什么建议吗

#include <stdio.h>

#define STACK_SIZE 50
#define MAX_INPUT_SIZE 1000
#define FALSE 0
#define TRUE !FALSE

void get_input();
int valid_input();

int main() {
  char user_input[MAX_INPUT_SIZE + 1]; // +1 for the \0

  get_input(user_input);

  if (valid_input(user_input))
    printf("Success\n");
  else
    printf("Error\n");
}

// Functions
void get_input(char* output) {
  int c, i;
  for(i=0; (c = getchar()) != '\n' && c != EOF && i <= MAX_INPUT_SIZE; i++)
    output[i] = c;
  output[i] = '\0';
}

int valid_input(char* input) {
  char stack[STACK_SIZE];
  char c;
  int i = 0;
  int stack_index = -1;

  while ((c = input[i]) != '\0' && i < STACK_SIZE) {
    switch(c){
      case '[': case '(': case '{':
        stack_index++; 
        stack[stack_index] = c;
        break;
      case ']': case ')': case '}':
        if ((c == ']' && stack[stack_index] != '[') ||
            (c == '}' && stack[stack_index] != '{') ||
            (c == ')' && stack[stack_index] != '('))
          return FALSE;

        // decrement the stack's index now that the closing bracket is found  
        stack_index--;
        break;
    }
    i++;
  }

  // stack index should be back where it started
  return (stack_index == -1);
}
#包括
#定义堆栈大小为50
#定义最大输入大小1000
#定义FALSE 0
#定义真!假
void get_input();
int有效_输入();
int main(){
char user_input[MAX_input_SIZE+1];//+1用于\0
获取输入(用户输入);
if(有效输入(用户输入))
printf(“成功”\n);
其他的
printf(“错误\n”);
}
//功能
无效获取_输入(字符*输出){
int c,i;

对于(i=0;(c=getchar())!='\n'&&c!=EOF&&i,您是否按enter键???并向我们显示整个代码,您可能没有正确调用getInput。并且,输出应该是char*。输出[++i]中的++意味着你跳过了数组中的一个条目——正如Pax Diablo指出的,通常是一个字符数组而不是int数组。其他人注意到你没有检查EOF,也没有检查缓冲区溢出。你现在应该开始学习好习惯了。Pax:我正在按enter键:)Jonathon:是的。C很容易读懂,但当你尝试这样做时,它会把你的头打个正着,至少这是我发现的。我以前就有过这样的想法,但是代码有一个问题,为了更容易找到问题,它被剥离了。标记解析器正在处理你的代码,把<作为html标记的开始…我很瘦把它放在一个代码块中(选择代码并按Ctrl-k)可能会有帮助,尽管我不确定。奇怪的是,这种行为似乎不可复制,至少在我的简单测试中是这样。首先,“char*userInput[MAX\u INPUT\u SIZE];”应该是“char userInput[MAX\u INPUT\u SIZE+1”;“-这是两个变化,char数组代替了char指针数组,还有用于保存null的额外空间。有趣的是,第一个问题掩盖了第二个问题,因为您分配的内存是所需内存的4倍。这可能不是您所拥有的确切代码,getInput接受char*,但您正在传入&userInput-您将得到一个编译错误,因为我是由于格式有问题,我删掉了一些代码。我现在发布了所有代码。它确实使用gcc 4.0.1在我的机器上编译,这是有意义的,否则我将传递指针的地址。不幸的是,我只是用textmate编写了这篇文章。今天晚些时候我将检查Eclipse并使用调试器。