【问题标题】:C: Memory error while running programC:运行程序时出现内存错误
【发布时间】:2015-12-14 18:20:13
【问题描述】:

我正在尝试编写一个接受字符串的程序(这些是给定的),然后根据它们的长度将它们存储在另一个数组中。在此之后,程序会打印出具有该长度的单词的数量。我尝试使用以下代码创建它:

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

void *repeatStr(char *str, int count); 

int main() {

char arr[8][128] = { "Hallo", "Stewardess", "wat", "een", "fijne", "vlucht" };  
int groottes[11] = { 0,0,0,0,0,0,0,0,0,0,0};

    for (size_t i = 0; i <= strlen(arr); i++)   {
        char *word =  arr[i] ;      
        int grootte = strlen(word);
        groottes[grootte] += 1; 
    }

    for (size_t i = 0; i < strlen(arr); i++)    {
        char ret;
        int grt = groottes[i];
        ret = repeatStr('*', grt);
        printf("%d: %s", i + 1, ret);   
     }
}


void *repeatStr(char *str, int count) {     
    if (count == 0) return "";
    char *ret = malloc(strlen(str) * count + count);
    if (ret == NULL) return NULL;
    strcpy(ret, str);
    while (--count > 0) {
    strcat(ret, str);   
  }     
  return ret; 
}

我得到的错误是:

在 Oefening.exe 中的 0x0FD53B8D (ucrtbased.dll) 处引发异常:0xC0000005:访问冲突读取位置 0x00000061。

【问题讨论】:

  • 会发生什么?是否抛出异常?什么是堆栈跟踪?
  • for (size_t i = 0; i &lt;= strlen(arr); i++) 我想你想要sizeof(arr) 这里
  • @Alexguitar - 我认为他实际上需要 (sizeof(arr)/sizeof(arr[0]) - 否则他将迭代 8*128 个条目:)
  • 这可以编译吗? repeatStr 期望 char * 但您将其传递给 char

标签: c out-of-memory


【解决方案1】:

鉴于此声明:

char arr[8][128] = { "Hallo", "Stewardess", "wat", "een", "fijne", "vlucht" };  

这两个循环严重错误:

for (size_t i = 0; i <= strlen(arr); i++)   {
    /* ... */
}

注意编译器警告,并在需要时打开它们。编译器应该警告您,在strlen(arr) 中,您正在传递一个指向strlen() 的指针,该指针与其参数类型不兼容。具体来说,您传递的是一个 char (*)[128](指向 128 个字符的数组的指针),而 strlen() 可能需要一个 -const char *

如果您想要arr (8) 中的元素数量,那将是@NadavL 建议的:sizeof(arr) / sizeof(arr[0])。鉴于您有 8 个元素的空间,但初始化器只有 6 个,我想您真正想要的是

for (size_t i = 0; (i < sizeof(arr) / sizeof(arr[0])) && arr[i][0]; i++)   {
    /* ... */
}

这确保i 不会超出数组边界,但如果在数组用完之前用完单词,则会停止迭代。后者是不可能的,因此如果您允许 C 为您选择数组大小,则无需检查它,而是像这样声明它:

char arr[][128] = { "Hallo", "Stewardess", "wat", "een", "fijne", "vlucht" };

【讨论】:

    【解决方案2】:

    首先

    char arr[8][128] = { ... };
    

    可以改成:

    char arr[][128] = { ... };  
    

    编译器可以看到您需要多少元素,因此当您省略第一个大小时,它会分配足够的元素。在您的情况下,您为 8 个字符串分配空间,而您只初始化其中的 6 个,这可能会导致以后出现问题。

    在前两个循环中,您要检查以下条件:

    i < sizeof(arr)/sizeof(arr[0])
    

    数组是零索引的,所以如果你的数组有 n 元素,你只能访问以下元素:

    arr[0], arr[1], ... , arr[n-1]
    

    sizeof(arr)arr 占用的总内存。如果您想要arr 中的数组数量,则必须将其除以其元素的大小,所以sizeof(arr[0])

    你拨打repeatStr的方式也有问题 它需要一个字符串,所以我假设你想用以下方式调用它:

    ret = repeatStr(arr[i], grt);
    

    ret 的定义如下:

    char *ret;
    

    因为它是一个字符串。

    【讨论】:

      【解决方案3】:

      在第一个循环中,您似乎想要遍历数组中的单词。

      但不是这样做,您将迭代 8*128 次,因为 sizeof(arr) 将返回 8*128(您分配了 128 个字节 8 次 - 每个字一个)。

      你真正想要使用的是:

          for (size_t i = 0; i <= (sizeof(arr)/sizeof(arr[0])); i++)
      

      这将在您的数组中产生正确数量的单词条目。

      另外,你使用:

      char ret;
      ret = repeatStr("*", grt);
      

      但是repeatStr返回一个char,然后你把'ret'当作一个char,即使在函数上下文中它只是一个普通的char。

      改为:

      char *ret;
      ret = repeatStr("*", grt);
      

      它应该可以编译和执行而不会违反内存。

      【讨论】:

      • 像这样使用 memset 只会删除数组的所有内容,虽然数组太长了
      • arr[8][128] = { "Hallo", "Stewardess", "wat", "een", "fijne", "vlucht" } 初始化所有arrmemset() 不需要。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-30
      • 2013-09-13
      • 2020-10-17
      • 1970-01-01
      • 2021-07-18
      相关资源
      最近更新 更多