简体   繁体   English

为什么malloc没有分配足够的内存?

[英]Why doesn't malloc allocate enough memory?

I am really stuck with one very simple piece of code. 我真的只限于一个非常简单的代码段。 This program takes argument like ./a.out -t=1,32,45,2 and prints quantity of commas in stdout. 该程序采用./a.out -t=1,32,45,2类的参数,并在stdout中输出逗号数量。 But from time to time execution works correctly and and more often throws segmentation fault. 但是执行有时会正确工作,并且更经常引发分段错误。

I figured out that problem in this line of function substr_cnt (I also placed corresponding commentaries in code below): 我在函数substr_cnt这一行中发现了这个问题(我还在下面的代码中放置了相应的注释):

target_counting = (char *)malloc(sizeof(char)*(strlen(target)));

In fact malloc returns NULL. 实际上,malloc返回NULL。 If I change sizeof(char) by sizeof(char *) all starts work like a charm but I can't understand why is that. 如果我将sizeof(char)更改为sizeof(char *)所有启动都像sizeof(char *)一样,但是我不明白为什么会这样。 Furthermore in main function I also use malloc, and even with the same line 此外,在主函数中,我还使用了malloc,甚至在同一行中

arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3)));

all works just fine. 一切正常。

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

#define strindex(target, source) ((size_t) strstr(target, source) - (size_t) target)

int substr_cnt( char *target, char *source ) {
    int i=0;
    int cnt=0;
    char *target_counting;
    //this is NOT working
    target_counting = (char *)malloc(sizeof(char)*(strlen(target)));
    //this is working
    //target_counting = (char *)malloc(sizeof(char *)*(strlen(target)));

    if (target_counting == NULL) {
        printf("malloc failed\n");
        return -1;
    }
    strcpy(target_counting, target);
    while ((i=strindex(target_counting, source)) > 0) {
        strncpy(target_counting, target_counting + i + 1, strlen(target_counting));
        cnt++;
    }
    free(target_counting);
    return cnt;
}

int main( int argc, char *argv[] )
{
    int i;
    int default_behavior = 0;
    int arg_parametr_cnt;
    char *arg_parameter; 
    if (argc == 1) {
        default_behavior = 1;
    } else if (argv[1][0] == '-' && argv[1][1] == 't' && argv[1][2] == '=') {
        //this is working
        arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3)));
        strncpy(arg_parameter, argv[1]+3, strlen(argv[1]));
        printf("%s\n", arg_parameter);
        arg_parametr_cnt = substr_cnt(arg_parameter, ",");
        printf("commas: %d\n", arg_parametr_cnt);
    }
    else {
        printf("wrong command line");
        return 1;
    } 
    return 0;
}

You have several issues here, the main point, you don't need to allocate memory at all. 这里有几个问题,重点是,您根本不需要分配内存。 You can implement searching for a given substring without modifying the string and therefore work directly on the given argv parameters, eg 您可以实现搜索给定的子字符串而无需修改字符串,因此可以直接在给定的argv参数上工作,例如

int substr_cnt(const char *haystack, const char *needle)
{
    int cnt = 0;
    const char *found = haystack;
    while ((found = strstr(found, needle)) != NULL) {
        ++found;
        ++cnt;
    }

    return cnt;
}

Same for the call in main , just pass argv directly main的调用相同,只是直接传递argv

arg_parametr_cnt = substr_cnt(argv[1] + 3, ",");

Now to answer your question, unless you really see the output of 现在回答您的问题,除非您真的看到了输出

printf("malloc failed\n");

I don't believe, malloc returns NULL , because when you allocate an even larger amount of memory, sizeof(char*) vs sizeof(char) , it works. 我不相信, malloc返回NULL ,因为当您分配更大的内存时, sizeof(char*) vs sizeof(char)可以工作。

The reasons, why your program crashes, are already covered in the other answers. 其他答案中已经介绍了导致程序崩溃的原因。 To summarize 总结一下

  • target_counting = (char *)malloc(sizeof(char)*(strlen(target))); allocates one char less than it should 分配的char少于应有的数量
  • while ((i=strindex(target_counting, source)) > 0) I'm not sure, what happens, when the result of strstr is NULL . while ((i=strindex(target_counting, source)) > 0)我不确定,当strstr的结果为NULL时会发生什么。 strindex might return a negative number, depending on your memory layout, but I am not sure. strindex 可能会返回负数,具体取决于您的内存布局,但是我不确定。
  • strncpy(target_counting, target_counting + i + 1, strlen(target_counting)); This is not really an issue, but since you copy the rest of the string, you could use strcpy(target_counting, target_counting + i + 1) instead. 这并不是真正的问题,但是由于您复制了字符串的其余部分,因此可以改用strcpy(target_counting, target_counting + i + 1)
  • arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3))); this should be malloc(sizeof(char) * strlen(argv[1]) - 3 + 1) 这应该是malloc(sizeof(char) * strlen(argv[1]) - 3 + 1)
  • strncpy(arg_parameter, argv[1]+3, strlen(argv[1])); again strcpy(arg_parameter, argv[1]+3) would be sufficient 再次strcpy(arg_parameter, argv[1]+3)就足够了

Update: 更新:

In this version 在这个版本中

int strindex(char *target, char *source)
{
    char *idx;
    if ((idx = strstr(target, source)) != NULL) {
        return idx - target;
    } else {
        return -1;
    }
}

you have an explicit test for NULL and act accordingly. 您对NULL有一个明确的测试,并采取相应的措施。

In the macro version 在宏版本中

#define strindex(target, source) ((size_t) strstr(target, source) - (size_t) target)

there is no such test. 没有这样的测试。 You determine the index by calculating the difference between strstr() and the base address target . 您可以通过计算strstr()与基地址target的差来确定索引。 This is fine so far, but what happens, when strstr() returns NULL ? 到目前为止,这还不错,但是当strstr()返回NULL时会发生什么?

Pointer arithmetic is defined with two pointers, pointing into the same array. 指针算术由指向同一数组的两个指针定义。 As soon as the two pointers point into different arrays, or one pointing into an array and the other somewhere else, the behaviour is undefined. 一旦两个指针指向不同的数组,或者一个指针指向一个数组,另一个指针指向其他位置,则该行为是不确定的。

Technically, when you calculate NULL - target , it might yield a negative value, but it also might not. 从技术上讲,当您计算NULL - target ,它可能会产生负值,但也可能不会。 If target points to the address of 0x0f0a3a90 , you could have 0x0 - 0x0f0a3a90 and get a negative value. 如果target指向地址0x0f0a3a90 ,则可能为0x0 - 0x0f0a3a90并得到负值。 If target points to 0xfe830780 however, it might be interpreted as a negative number, and then 0x0 - 0xfe830780 could result in a positive number. 但是,如果target指向0xfe830780 ,则它可能会解释为负数,然后0x0 - 0xfe830780可能会导致正数。

But the main point is, you have undefined behaviour. 但要点是,您的行为不确定。 For further reading look for pointer arithmetic , eg C++: Pointer Arithmetic 要进一步阅读,请查找指针算法 ,例如C ++:Pointer Arithmetic

your malloc is not allocating space for the null terminator, you need to malloc (strlen(string)+1). 您的malloc没有为空终止符分配空间,您需要malloc(strlen(string)+1)。 The malloc with a char* works because a pointer (is normal) 4 bytes long, so you are allocating 4 times more memory than required - minus the 1 byte need for a null terminator. 带char *的malloc之所以起作用,是因为指针(正常)为4个字节长,因此您分配的内存是所需内存的4倍-减去空终止符所需的1个字节。

The problem may lie here: malloc(sizeof(char)*(strlen(argv[1] - 3)) in main . You are subtracting 3 from argv[1] . I think you intended to use: 问题可能出在这里: malloc(sizeof(char)*(strlen(argv[1] - 3))main你减去。 3argv[1]我想你打算使用:

malloc(sizeof(char)*(strlen(argv[1]) - 2)); // Allocate one more space for '\\0' character

Doing this makes strlen to access unallocated memory. 这样做会使strlen访问未分配的内存。

Your program may not fail here, but later, because it is simply undefined behavior . 您的程序在这里可能不会失败,但是稍后,因为它只是undefined behavior

There are several buffer overruns, but I think that the bug that makes you program crash is the following: 有几个缓冲区溢出,但是我认为导致程序崩溃的错误如下:

    strncpy(target_counting, target_counting + i + 1, strlen(target_counting));

Note that the strings in strncpy may not overlap! 请注意,strncpy中的字符串可能不会重叠!

I suggest that you do a memmove instead, because memmove can handle overlapping buffers: 我建议您改用memmove,因为memmove可以处理重叠的缓冲区:

    memmove(target_counting, target_counting + i + 1, strlen(target_counting + i + 1) + 1);

I think your main issue is here : 我认为您的主要问题在这里:

 arg_parameter = (char *) malloc(sizeof(char)*(strlen(argv[1] - 3)));

especially here 特别是在这里

 strlen(argv[1] - 3)

you pass to strlen address of argv[1]-3 which is not valid address. 您传递给无效地址argv[1]-3 strlen地址。 actually what you meant is strlen(argv[1]) - 3 . 实际上,您的意思是strlen(argv[1]) - 3 As others said you also should add one char for \\0 so strlen(argv[1]) - 2 正如其他人所说,您还应该为\\0添加一个字符,因此strlen(argv[1]) - 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM