【问题标题】:My Loop Won't Check All Elements Of Array in C我的循环不会检查 C 中数组的所有元素
【发布时间】:2016-04-07 04:28:27
【问题描述】:
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void displayString (const char *sPtr);
void getString (char *[]);
int determinIfConvert (char);

int main ()
{
    char originalString[11] = { 0 };
    char convertedString[11];
    getString (originalString);
    displayString (originalString);

    // this loop runs through the "originalString" to check for the char: 'a'
    for (int i = 0; i < 11; i++) {
        determinIfConvert (originalString[i]);
    }
    system ("pause");
}

void getString (char *a[])  // this function gets a string
{
    printf ("enter 11 char string: \n");
    scanf ("%s", a);
}

// this program displays the inputstring
void displayString (const char *sPtr)
{
    for (; (*sPtr != '\0'); ++sPtr) {
        printf ("%c", *sPtr);
    }
}

int determinIfConvert (char *a)
{
    if (a == 97)            // this is a test condition. The goal is to
                            // check for all lowercase, but now i'm
                            // only entering "aaaaa"
    {
        printf ("Works");   // if it prints multiple"works"
                            // then i can continue my program
                            // but it only prints ONE "works" and freezes.
    }

}

目前我在main() 中的 For 循环有问题,没有完成。目标是输入一串字符,然后检查小写字符。这将通过函数DeterminIfConvert(char) 完成。但是,当我逐个元素地遍历循环时,它会在第二个元素之后冻结。我的测试数据是“aaaa”,它会打印“aaaa”,所以我知道我的前两个函数工作得很好。我进入循环,它通过第一个元素,打印“作品”然后冻结。 :/

【问题讨论】:

  • 在调用任何scanf() 系列函数时: 1) 始终检查返回值(而不是参数值)以确保操作成功。 2) 使用 '%s' 输入格式说明符时,始终包含比输入缓冲区长度小 1 的最大长度修饰符,因此用户不能溢出输入缓冲区,导致未定义的行为并可能导致 seg故障事件..
  • 关于这一行:printf ("enter 11 char string: \n"); 输入缓冲区只有 11 个字符长,下面的 '%s' 格式说明符将导致 scanf() 始终将 NUL 字节附加到用户输入的任何内容。所以字符串的最大长度只能是10个字符:建议:1)将11改为10 2)将scanf()的调用修改为:if( 1 != scanf ("%10s", a) ) { // handle error }
  • 检查小写,给定ascii字符,使用islower()
  • 关于这一行:void getString (char *a[]) 这表示它正在传递一个指向 char 的指针数组。不是你想要的。建议:void getString (char *a)
  • 这一行:for (int i = 0; i &lt; 11; i++) { 将检查一个太远的数组。建议:for (int i = 0; originalString[i]; i++) {

标签: c arrays loops for-loop


【解决方案1】:

多个错误

void getString(char *a[])

应该是

void getString(char a[])

由于您发送的是array of char 的基地址,而不是array of pointer to char

char *a[];  // array of pointer to char
char a[];   // array of char

 int determinIfConvert(char *a)

应该是

int determinIfConvert(char a)

因为您发送的是char,而不是pointer to char

char * a;    // pointer to char
char a;      // char

注意: 使用main()的标准定义

int main(void) //if no command line arguments.

【讨论】:

    【解决方案2】:

    如果您输入的是 11 个字符的字符串,那么您应该这样做:

    char originalString[12] = { 0 };
    

    这是因为您还需要 1 个字符来存储空字符 '\0'

    这可能就是为什么在您的函数 getString(...) 中,指针超出了数组边界并可能调用未定义的行为。

    最后,getString(...) 的函数原型应该是

    void getString(char a[]); //without the *
    

    【讨论】:

      【解决方案3】:

      除了其他答案之外,您还有其他几个方面可以改进您的代码。

      避免在代码中使用幻数(例如11)。而是为字符串中的最大字符定义一个常量#define MAXC 11,或者您可以使用enum 而不是enum { MAXC = 11 };

      就目前而言,您无法防止 11 character 数组溢出(这意味着您的用户最多可以输入 10 characters 以及 nul-terminating 字符的空间)。为了防止用户输入超过10 的内容,您应该使用带有scanf 的field-width 说明符:

          scanf ("%10s", a);
      

      这并不能解决您对scanf 的问题。您必须每次检查退货以确保发生预期的转化次数,例如:

      if (scanf ("%10s", a) != 1) {
          fprintf (stderr, " -> error: invalid input.\n");
          exit (EXIT_FAILURE);
      }
      

      这更好,但是使用%s,您无法读取包含空格的字符串,并且您仍然在输入缓冲区中留下一个尾随'\n'。如果用户输入"my dog",您只存储"my"。要解决部分问题,您可以使用格式说明符"%10[^\n]%*c"。但是,如果用户在没有其他输入的情况下按下 [Enter],则必须防止出现无限循环。要解决所有问题,并防止在输入缓冲区中留下尾随换行符,您可以使用以下内容:

      int getString (char *a)  // this function gets a string
      {
          int c, rtn = 0;
          printf ("enter string (10 char or less): ");
          while ((rtn = scanf ("%10[^\n]%*c", a)) != 1) {
              if (rtn == EOF)
                  break;
              fprintf (stderr, " -> error: invalid input, try again..\n");
              printf ("enter string (10 char or less): ");
              /* flush input buffer - to avoid endless loop */
              while ((c = getchar()) != '\n' && c != EOF) {}
          }
      
          return rtn;
      }
      

      所有这些都暴露了使用scanf 进行用户输入的困难。更好的方法可能是使用fgets(或getline)来读取完整的输入行。

      无论您使用scanf 还是fgets 等,您都必须花一些时间和精力来编写您的输入处理程序,以确保您尝试涵盖用户可能弄乱输入的所有方式。下面fgets 仅用于提供替代方案。您还应该选择一种返回类型,以便您判断是否已成功接收输入。它也可能是一个有用的返回,例如输入的长度等。

      您的指针间接问题级别的其余部分已由其他答案解决。综上所述,您可以执行以下操作:

      #define _CRT_SECURE_NO_WARNINGS
      
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      #define MAXC 11
      
      void displayString (const char *sPtr);
      int getString (char *);
      int determinIfConvert (char);
      
      int main (void)
      {
          char originalString [MAXC] = "";
          // char convertedString[MAXC] = "";  /* currently unused */
          if (!getString (originalString)) {
              fprintf (stderr, "error: getString failed.\n");
              return 1;
          }
          displayString (originalString);
      
          // this loop runs through the "originalString" to check for the char: 'a'
          for (int i = 0; i < 11; i++) {
              determinIfConvert (originalString[i]);
          }
          system ("pause");
          return 0;          /* main() is type 'int' and returns a value */
      }
      
      int getString (char *a)  // this function gets a string
      {
          char *p = a;
          int c;
          size_t len = 0;
      
          printf ("enter string (10 char or less): ");
          for (;;) {
              p = fgets (a, MAXC, stdin);
              if (!p) break;          /* handle [CTRL+D]  */
              if (*p == '\n') {       /* handle empty str */
                  fprintf (stderr, " -> error: invalid input, try again..\n");
                  printf ("enter string (10 char or less): ");
                  continue;
              }
              /* trim newline/flush input buffer */
              len = strlen (p);
              if (len && a[len - 1] == '\n')
                  a[--len] = 0;
              else  /* user entered more than 10 chars */
                  while ((c = getchar()) != '\n' && c != EOF) {}
              break;
          }
      
          return (int) len;
      }
      
      // this program displays the inputstring
      void displayString (const char *sPtr)
      {
          for (; *sPtr; sPtr++) {
              printf ("%c", *sPtr);
          }
          putchar ('\n');
      }
      
      int determinIfConvert (char a)
      {
          if (a == 97)
              printf ("Works\n");
          return 0;
      }
      

      使用/输出示例

      $ ./bin/getdispstr
      enter string (10 char or less): my dog has fleas
      my dog has
      Works
      
      $ ./bin/getdispstr
      enter string (10 char or less):
       -> error: invalid input, try again..
      enter string (10 char or less): my dog has fleas, my cat has none.
      my dog has
      Works
      

      使用 CTRL+D (EOF)

      $ ./bin/getdispstr
      enter string (10 char or less): error: getString failed.
      

      有很多方法可以做到这一点,这只是一个例子。查看所有答案,如果您有任何问题,请告诉我。

      【讨论】:

        【解决方案4】:

        这个

          char originalString[11] = { 0 };
        

        紧随其后

        for (int i = 0; i < 11; i++)
            {
                determinIfConvert(originalString[i]);
            }
        

        导致问题。您会看到 char 数组在index 0 之后没有元素。是的,我相信你试图尝试的东西 getString(originalString); 似乎您想从用户输入中获取 originalString,这在您的情况下未正确执行。

        【讨论】:

          【解决方案5】:

          您将 char 类型的对象传递给接受 char*

          的函数
           char originalString[11] = { 0 };
           determinIfConvert(originalString[i]);
          
           int determinIfConvert(char *a)
          

          【讨论】:

            【解决方案6】:

            字符串只不过是一组以空字符结尾的字符,因此如果您希望字符串中有 11 个字符,您应该分配 12 个字节给您的 数组,即你可以改变:

            char originalString[11] = { 0 };
            

            char originalString[12] = ""; 
            
            /* Here is the string is empty but because you use double quotes  
             * compiler understands that you are initializing a string, so '\0' is auto  
             * appended to the end of it by the compiler to mark the end of the string.
             */
            

            convertedString[11] 的情况也是如此,将其更改为

            char convertedString[12] = ""; 
            

            改变

            void getString(char *a[]); 
            

            void getString(char a[]); //char *a is also fine
            

            改变

            int determinIfConvert(char *a)
            

            int determinIfConvert(char a) // You wish to check a character
            

            你可能希望替换

            scanf("%s", a);
            

            fgets(a,12,stdin);
            

            因为 scanf 不能检查溢出但 fgets 可以。在这里,字符串中最多可以有 11 个字符。如果发生溢出,输入的其余部分将被修剪,并将 '\0' 分配给第 12 个字节。

            您可能希望使用islower 函数来检查一个字符是否为小写。所以你可以改变

            if (a == 97)
            

            if (islower(a)) // check if a character is lowercase.
            

            请记住,您可能需要包含 string.h 标头才能使用 islower()

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-01-13
              • 2013-12-31
              • 1970-01-01
              相关资源
              最近更新 更多