【问题标题】:C - out of bounds for type stringC - 字符串类型越界
【发布时间】:2018-02-22 01:23:14
【问题描述】:

我正在尝试解决 CS50 的一些问题集。我需要提取字符串“stra”的前两个字符,然后将它们连接起来并转换为字符串,然后将该字符串与数组中的字符串进行比较。我已经大量阅读,在 C 中没有字符串,只有字符数组,但在 CS50 中它们使用字符串声明类型。当我运行代码时,它给了我以下错误

运行时错误:类型“字符串 [4]”的索引 4 超出范围

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

int main(void){

   string stra = "GH7";

   int x = 0;
   //extract first two chars of stra
   char strb[3] = {stra[0], stra[1], '\0'};
   //concatenate chars
   string strc = strb;

   string letters[] = {"AB","CD","ED","GH"};

   for (int i = 0, n = sizeof(letters); i < n; i++)
   {
      if (strc == letters[i])  // <--the error happens here
      {
         break;
      }
      else
      {
         x++;
      }
   }
   printf("%i", x);
}

它给了我这个错误

运行时错误:类型“字符串 [4]”的索引 4 超出范围

【问题讨论】:

    标签: c cs50


    【解决方案1】:

    问题在于初始化

    n = sizeof(letters)
    

    sizeof(letters) 应除以单个元素(指针)的大小:

    n = sizeof(letters) / sizeof(*letters)
    

    (除非您确定 letters 指向一个字符串字面量,这是多余的,这是计算字面量数组大小的最佳方法,它甚至可以跟随可能的类型更改)

    【讨论】:

      【解决方案2】:

      您想要遍历元素“字符串”数组letters。 要计算元素个数,最好的方法是用数组的大小除以第一个元素的大小。

      请看下面的例子:

      //#include <cs50.h>
      #include <stdio.h>
      #include <string.h>
      
      int main(void){
      
          char *stra = "GH7";
      
          int x = 0;
          //extract first two chars of stra
      
          char strb[3] = {stra[0], stra[1], '\0'};
      
          //concatenate chars
          char *strc = strb;
      
          printf("strc: %s\n", strc);
      
          char * letters[] = {"AB","CD","ED","GH"};
      
          // number of element in the `letters` 
      
          int nr_of_elements = sizeof(letters)/sizeof(letters[0]);
      
          printf("sizeof letters= %d,  sizeof the element= %d   nr_of_elements= %d \n", sizeof(letters), sizeof(letters[0]), nr_of_elements);
      
          for (int i = 0, n = nr_of_elements;  i < n;  i++)
          {
            if (strc == letters[i])  // <--the error happens here
            {
               break;
            }
           else
            {
               x++;
            }
          }
      
          printf("x= %i", x);
          return 0;
      }
      

      输出:

      strc: GH
      sizeof letters= 32,  sizeof the element= 8   nr_of_elements= 4 
      x= 4
      

      【讨论】:

        【解决方案3】:

        string 是一个谎言。它是 char * 类型的 typedef(别名),不是字符串string 是一个字符序列,后跟一个 0 值终止符。字符串存储在char 的数组中(或wchar_t 用于“宽”字符串)。 char * 可能指向字符串中的第一个字符,或者它可能指向序列中不是字符串的第一个字符,或者它可能指向不属于任何序列的单个字符。它绝对是不是字符串string 类型的对象包含一个地址,而不是一个实际的字符串。

        它在 CS50.h 标头中的存在会造成混淆,并且会阻碍您学习正确的 C 字符串语义。如果您在这件事上有选择权,请不要使用它。

        无端吐槽>

        正如 Jean-Francois 指出的,sizeof 返回对象中的总字节数;如果要获取数组中元素的数量,必须将数组的总大小除以单个元素的大小:

        T arr[] = { /* some values of type T */ }; // for any type T
        size_t count = sizeof arr / sizeof arr[0]; // or divide by sizeof *arr
        

        记住sizeof 是一个操作符,而不是一个函数——如果操作数不是一个类型名,它就不需要用圆括号括起来(尽管它们并没有坏处) .

        请注意,这只适用于数组表达式,不适用于指针。请记住,在大多数情况下,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,并且表达式的值将是第一个元素的地址1。如果您尝试编写一个将数组作为参数并返回计数的函数,类似于

        size_t elt_count( int arr[] )
        {
          return sizeof arr / sizeof arr[0];
        }
        

        你不会得到你所期望的,因为在这种情况下arr 是一个指针,而不是一个数组2


        1. 除非它是sizeof 或一元&amp; 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则“T 的 N 元素数组”类型的表达式将被转换(“衰减”)为“指向T”类型的表达式,表达式的值将是数组第一个元素的地址。
        2. 在函数参数声明的上下文中,T a[N]T a[] 被解释为T *a;这三个都将a 声明为指向T 的指针。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-07-31
          • 2023-03-14
          • 2016-03-01
          • 2012-12-01
          • 2014-11-18
          • 1970-01-01
          • 2011-12-13
          • 2018-09-11
          相关资源
          最近更新 更多