C语言 括号、大括号、括号匹配中2项测试不合格

wz1wpwve  于 2023-11-16  发布在  其他
关注(0)|答案(1)|浏览(155)

我试图让所有的测试用例都通过,但是我总是得到很少或很多的测试用例,这取决于测试用例。我有一种感觉,就像我错过了一些重要的东西,但是经过无数个小时,我仍然不知道我错过了什么。
测试用例:12是字符串的数量,后面跟着字符串空行是第一个要测试的字符串。

  1. 12
  2. ([])
  3. (([()])))
  4. ([()[]()])()
  5. (([()])
  6. ([])
  7. (([()])))
  8. ([()[]()])()
  9. (
  10. (]
  11. )(
  12. ][

字符串
预期输出:

  1. Yes
  2. Yes
  3. No
  4. Yes
  5. No
  6. Yes
  7. No
  8. Yes
  9. No
  10. No
  11. No
  12. No


我的输出:

  1. Yes
  2. Yes
  3. No
  4. Yes
  5. Yes // should be no
  6. Yes
  7. No
  8. Yes
  9. Yes // should be no
  10. No
  11. No
  12. No


失败案例:

  1. ([])
  2. (


main.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "stack.h"
  4. void ClearKeyboardBuffer(void) {
  5. char c;
  6. int noc;
  7. noc = scanf("%c", &c);
  8. while (noc == 1 && c != '\n') {
  9. scanf("%c", &c);
  10. }
  11. }
  12. Boolean isMatch(void) {
  13. STACK hStack;
  14. int noc;
  15. char c;
  16. Boolean m = TRUE;
  17. hStack = StackInitDefault();
  18. if (hStack == NULL) {
  19. printf("Failed to allocate space for stack object.\n");
  20. exit(2);
  21. }
  22. noc = scanf("%c", &c);
  23. while (noc == 1 && c != '\n') {
  24. if (StackIsEmpty(hStack)) {
  25. if (c == '(' || c == '[' || c == '{') {
  26. StackPush(hStack, c);
  27. } else if (c == ')' || c == ']' || c == '}') {
  28. m = FALSE;
  29. }
  30. } else if (!StackIsEmpty(hStack)) {
  31. if (c == '(' || c == '[' || c == '{') {
  32. StackPush(hStack, c);
  33. } else if (c == ')' || c == ']' || c == '}') {
  34. if (c == ')' && StackTop(hStack, NULL) == '(') {
  35. StackPop(hStack);
  36. } else if (c == ']' && StackTop(hStack, NULL) == '[') {
  37. StackPop(hStack);
  38. } else if (c == '}' && StackTop(hStack, NULL) == '{') {
  39. StackPop(hStack);
  40. } else {
  41. m = FALSE;
  42. }
  43. }
  44. }
  45. noc = scanf("%c", &c);
  46. }
  47. return m;
  48. }
  49. int main(int argc, const char * argv[]) {
  50. STACK hStack;
  51. int n;
  52. hStack = StackInitDefault(); // initialize the object
  53. if (hStack == NULL) {
  54. printf("Failed to allocate space for stack object.\n");
  55. exit(1);
  56. }
  57. scanf("%d", &n); // get number of strings that the user will be inputting
  58. ClearKeyboardBuffer();
  59. while (n--) {
  60. if (isMatch()) {
  61. printf("Yes\n");
  62. } else {
  63. printf("No\n");
  64. }
  65. while (!StackIsEmpty(hStack)) {
  66. StackPop(hStack);
  67. }
  68. }
  69. StackDestroy(&hStack);
  70. return 0;
  71. }


stack.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "stack.h"
  4. #include "status.h"
  5. struct node;
  6. typedef struct node Node;
  7. struct node {
  8. char value;
  9. Node* next;
  10. };
  11. struct stack {
  12. Node* head;
  13. };
  14. typedef struct stack Stack;
  15. STACK StackInitDefault(void) {
  16. Stack* pStack = (Stack*)malloc(sizeof(Stack));
  17. if (pStack != NULL) {
  18. pStack->head = NULL;
  19. }
  20. return pStack;
  21. }
  22. Boolean StackIsEmpty(STACK hStack) {
  23. Stack* pStack = (Stack*)hStack;
  24. return (pStack->head == NULL)?TRUE:FALSE;
  25. }
  26. char StackTop(STACK hStack, Status* pStatus) {
  27. Stack* pStack = (Stack*)hStack;
  28. if (StackIsEmpty(hStack)) {
  29. if (pStatus != NULL) {
  30. *pStatus = FAILURE;
  31. }
  32. return 'e';
  33. }
  34. if (pStatus != NULL) {
  35. *pStatus = SUCCESS;
  36. }
  37. return pStack->head->value;
  38. }
  39. Status StackPush(STACK hStack, char c) {
  40. Stack* pStack = (Stack*)hStack;
  41. Node* temp = (Node*)malloc(sizeof(Node));
  42. if (temp == NULL) {
  43. return FAILURE;
  44. }
  45. temp->value = c;
  46. temp->next = pStack->head;
  47. pStack->head = temp;
  48. return SUCCESS;
  49. }
  50. Status StackPop(STACK hStack) {
  51. Stack* pStack = (Stack*)hStack;
  52. Node* temp;
  53. if (StackIsEmpty(hStack)) {
  54. return FAILURE;
  55. }
  56. temp = pStack->head;
  57. pStack->head = pStack->head->next;
  58. free(temp);
  59. return SUCCESS;
  60. }
  61. void StackDestroy(STACK* phStack) {
  62. Stack* pStack = (Stack*)*phStack;
  63. Node* temp = pStack->head;
  64. while (pStack->head != NULL) {
  65. temp = pStack->head;
  66. pStack->head = pStack->head->next;
  67. free(temp);
  68. }
  69. free(pStack);
  70. *phStack = NULL;
  71. }


stack.h

  1. #ifndef stack_h
  2. #define stack_h
  3. #include "status.h"
  4. typedef void* STACK;
  5. STACK StackInitDefault(void);
  6. Status StackPush(STACK hStack, char c);
  7. Status StackPop(STACK hStack);
  8. char StackTop(STACK hStack, Status* pStatus);
  9. void StackDestroy(STACK* phStack);
  10. Boolean StackIsEmpty(STACK hStack);
  11. #endif /* stack_h */


status.h

  1. #ifndef STATUS_H
  2. #define STATUS_H
  3. enum status { FAILURE, SUCCESS };
  4. typedef enum status Status;
  5. enum boolean { FALSE, TRUE };
  6. typedef enum boolean Boolean;
  7. #endif

piwo6bdm

piwo6bdm1#

这些评论基本上涵盖了这里的所有问题,但我将尝试进行总结。
主要的问题是,为了使表达式平衡,在表达式完成解析后,堆栈应该被检查为 * 空 *。这在代码中没有完成。
第二个问题是,您对某些测试用例的期望似乎是错误的(例如,将(([()])))期望为Yes)。
其他问题包括:
main中的STACK hStack;isMatch中的STACK hStack;不是同一个对象。isMatch中的对象永远不会传递给StackDestroy,而main中的对象是无意义的。
最普遍的问题之一是,在这段代码中有相当多的重复。

  1. if (StackIsEmpty(hStack)) {
  2. /* ... */
  3. } else if (!StackIsEmpty(hStack)) {
  4. /* ... */

字符串
分支条件可以通过一个else语句来暗示。
isMatch的整个push & pop部分花费大量时间检查不必要或冗余的条件。

  • 给定一个开始字符(([{),将其压入堆栈。
  • 给定一个结束字符()]}),如果堆栈为空,或者堆栈顶部不是相关的 * 开始字符 *,则返回 invalid 结果。

您可以有效地使用 * 行 * 的输入,但是通过从标准输入中一次阅读一个字符来实现。至少,人们可能会建议使用getchar而不是使用scanf("%c", ...),但是如果不提到使用fgets阅读整行的可能性,那将是疏忽,然后将其处理为 string。只要你的行不是 * 非常 * 长,这是非常简单的。
一些明确的 * 类/课程/教师/教授 * 具体的批评,考虑到这一评论:
老实说,我不确定。我同意很多东西看起来有点无意义,但教授真的很老派,他希望我们练习将堆栈对象视为不透明对象。这不是我个人编写这个程序的方式,但这是他希望我们这样做的方式。
这两个基本上都是噪音:

  1. enum status { FAILURE, SUCCESS };
  2. typedef enum status Status;
  3. enum boolean { FALSE, TRUE };
  4. typedef enum boolean Boolean;


这两种枚举都可以很容易地用bool类型表示:truefalse从C99到<stdbool.h>(C23将使它们成为keywords)。
typedef

  1. typedef void* STACK;


不太好。void *不需要促进不透明类型。不透明类型本质上只是指向 * 不完整类型 *(没有定义的可识别类型,即关于其大小的信息)的指针。对于不透明类型,您的标头可以简单地包含

  1. typedef struct stack Stack;
  2. Stack *StackInitDefault(void);


使用源文件中的struct stack定义。
此外,typedef-ing指针有点争议,但最常见的建议是避免这样做。最重要的是,不需要显式转换void *到另一个指针类型,因为void *可以 * 隐式 * 转换为任何其他指针类型。
(* 如果你的编译器在抱怨,你可能使用的是C++编译器,而不是C编译器。
同样,尽你所能通过这门课,但其中一些要求不是好的做法。
下面是一个遵循上面大部分建议的实现。它避免了typedef-ing。StackTop不存在,因为它不需要。它只是检查所有输入行(而不是从第一行派生的一组行数),或者运行当前的测试用例。
一些典型的边缘案例:传递空指针到任何库函数,或弹出空堆栈都是undefined behaviourStackDestroy将其参数作为dangling-pointer留给调用者处理(模仿free)。
示例用法:

  1. $ ./a.out tests
  2. "" -> PASS
  3. "([])" -> PASS
  4. "(([()])))" -> PASS
  5. "([()[]()])()" -> PASS
  6. "(([()])" -> PASS
  7. "(([()])" -> PASS
  8. "(([()])))" -> PASS
  9. "([()[]()])()" -> PASS
  10. "(" -> PASS
  11. "(]" -> PASS
  12. ")(" -> PASS
  13. "][" -> PASS
  1. $ ./a.out
  2. []
  3. "[]" true
  4. ({[]})
  5. "({[]})" true
  6. int main(int argc, char *argv[]) { puts("Hello world!"); }
  7. "int main(int argc, char *argv[]) { puts("Hello world!"); }" true
  8. )()(((){}{})()
  9. ")()(((){}{})()" false

代码:
stack.h

  1. #ifndef STACK_H
  2. #define STACK_H
  3. #include <stdbool.h>
  4. struct stack;
  5. struct stack *StackInitDefault(void);
  6. bool StackIsEmpty(struct stack *);
  7. bool StackPush(struct stack *, char);
  8. char StackPop(struct stack *);
  9. void StackDestroy(struct stack *);
  10. #endif


stack.c

  1. #include <stdlib.h>
  2. #include "stack.h"
  3. struct node {
  4. char value;
  5. struct node *prev;
  6. };
  7. struct stack {
  8. struct node *top;
  9. };
  10. struct stack *StackInitDefault(void)
  11. {
  12. return calloc(1, sizeof (struct stack));
  13. }
  14. bool StackIsEmpty(struct stack *s)
  15. {
  16. return !s->top;
  17. }
  18. bool StackPush(struct stack *s, char c)
  19. {
  20. struct node *n = malloc(sizeof *n);
  21. if (!n)
  22. return false;
  23. n->value = c;
  24. n->prev = s->top;
  25. s->top = n;
  26. return true;
  27. }
  28. char StackPop(struct stack *s)
  29. {
  30. struct node *n = s->top;
  31. char value = n->value;
  32. s->top = n->prev;
  33. free(n);
  34. return value;
  35. }
  36. /* slightly inefficient being written in terms of `StackPop`,
  37. * but keeps things simple */
  38. void StackDestroy(struct stack *s)
  39. {
  40. while (!StackIsEmpty(s))
  41. (void) StackPop(s);
  42. free(s);
  43. }


main.c

  1. #include <stdbool.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "stack.h"
  6. #define stringify(b) ((b) ? "true" : "false")
  7. /* running out of memory renders this program useless
  8. * bail out, let the OS clean up */
  9. static void fatal_memory(void)
  10. {
  11. fputs("CRITICAL: Out of memory.\n", stderr);
  12. exit(EXIT_FAILURE);
  13. }
  14. static char invert(char c)
  15. {
  16. switch (c) {
  17. case '(': return ')';
  18. case '[': return ']';
  19. case '{': return '}';
  20. }
  21. return '\0';
  22. }
  23. static bool is_balanced(const char *data)
  24. {
  25. struct stack *st = StackInitDefault();
  26. if (!st)
  27. fatal_memory();
  28. for (char c; (c = *data); data++) {
  29. switch (c) {
  30. case '(':
  31. case '[':
  32. case '{':
  33. if (!StackPush(st, c))
  34. fatal_memory();
  35. break;
  36. case ')':
  37. case ']':
  38. case '}':
  39. if (StackIsEmpty(st) || invert(StackPop(st)) != c) {
  40. StackDestroy(st);
  41. return false;
  42. }
  43. break;
  44. }
  45. }
  46. bool result = StackIsEmpty(st);
  47. StackDestroy(st);
  48. return result;
  49. }
  50. static void do_basic_testcases(void)
  51. {
  52. const struct {
  53. const char *string;
  54. const bool expect;
  55. } tests[] = {
  56. { "", true },
  57. { "([])", true },
  58. { "(([()])))", false },
  59. { "([()[]()])()", true },
  60. { "(([()])", false },
  61. { "(([()])", false },
  62. { "(([()])))", false },
  63. { "([()[]()])()", true },
  64. { "(", false },
  65. { "(]", false },
  66. { ")(", false },
  67. { "][", false }
  68. };
  69. for (size_t i = 0; i < sizeof tests / sizeof *tests; i++) {
  70. bool expect = tests[i].expect;
  71. bool actual = is_balanced(tests[i].string);
  72. printf("\"%s\" -> ", tests[i].string);
  73. if (expect == actual)
  74. puts("PASS");
  75. else
  76. printf("FAIL: `%s` expected, got `%s`\n", stringify(expect), stringify(actual));
  77. }
  78. }
  79. int main(int argc, char **argv)
  80. {
  81. if (argc > 1 && 0 == strcmp("tests", argv[1]))
  82. do_basic_testcases();
  83. else {
  84. char line[4096];
  85. while (fgets(line, sizeof line, stdin)) {
  86. line[strcspn(line, "\n")] = '\0';
  87. printf("\"%s\" %s\n", line, stringify(is_balanced(line)));
  88. }
  89. }
  90. }

展开查看全部

相关问题