return 字符串的 C 函数导致顶部大小损坏

C Function to return a String resulting in corrupted top size

我正在尝试编写一个调用[外部库 (?)] 的程序 (我不确定我在这里使用的术语是否正确)我也在写信来清理提供的字符串。例如,如果要为我的 main.c 程序提供一个字符串,例如:

asdfFAweWFwseFL Wefawf JAWEFfja FAWSEF

它会调用 externalLibrary.c 中的一个函数(暂且称它为 externalLibrary_Clean),该函数将接受字符串,并且 return 所有字符均为大写且不带空格:

ASDFFAWEWFWSEFLWEFAWFJAWEFFJAFAWSEF

最疯狂的是我可以正常工作...只要我的字符串长度不超过 26 个字符。一旦我添加了第 27 个字符,我就会得到一个错误,上面写着 malloc(): corrupted top size.

这里是externalLibrary.c:

#include "externalLibrary.h"
#include <ctype.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>

char * restrict externalLibrary_Clean(const char* restrict input) {
    // first we define the return value as a pointer and initialize
    // an integer to count the length of the string
    char * returnVal = malloc(sizeof(input));
    char * initialReturnVal = returnVal; //point to the start location

    // until we hit the end of the string, we use this while loop to
    // iterate through it
    while (*input != '[=11=]') {
        if (isalpha(*input)) {  // if we encounter an alphabet character (a-z/A-Z)
                                // then we convert it to an uppercase value and point our return value at it
            *returnVal = toupper(*input);
            returnVal++; //we use this to move our return value to the next location in memory
            
        }
        input++; // we move to the next memory location on the provided character pointer
    }

    *returnVal = '[=11=]'; //once we have exhausted the input character pointer, we terminate our return value

    return initialReturnVal;
}

int * restrict externalLibrary_getFrequencies(char * ar, int length){
    static int freq[26];
    for (int i = 0; i < length; i++){
        freq[(ar[i]-65)]++;
    }
    return freq;
}

它的头文件 (externalLibrary.h):

#ifndef LEARNINGC_EXTERNALLIBRARY_H
#define LEARNINGC_EXTERNALLIBRARY_H

#ifdef __cplusplus
extern "C" {
#endif

char * restrict externalLibrary_Clean(const char* restrict input);
int * restrict externalLibrary_getFrequencies(char * ar, int length);

#ifdef __cplusplus
}
#endif

#endif //LEARNINGC_EXTERNALLIBRARY_H

我的 main.c 文件来自所有操作发生的地方:

#include <stdio.h>
#include "externalLibrary.h"

int main() {
    char * unfilteredString = "ASDFOIWEGOASDGLKASJGISUAAAA";//if this exceeds 26 characters, the program breaks 
    char * cleanString = externalLibrary_Clean(unfilteredString);
    //int * charDist = externalLibrary_getFrequencies(cleanString, 25); //this works just fine... for now

    printf("\nOutput: %s\n", unfilteredString);
    printf("\nCleaned Output: %s\n", cleanString);
    /*for(int i = 0; i < 26; i++){
        if(charDist[i] == 0){

        }
        else {
            printf("%c: %d \n", (i + 65), charDist[i]);
        }
    }*/

    return 0;
}

我非常精通 Java 编程,我正在尝试将我的知识转化为 C,因为我希望更详细地了解我的计算机如何工作(并更好地控制诸如此类的事情作为记忆)。

如果我在 Java 中解决这个问题,它就像创建两个 class 文件一样简单:一个名为 main.java 和一个名为 externalLibrary.java,其中我会 static String Clean(string input) 然后在 main.java 中用 String cleanString = externalLibrary.Clean(unfilteredString).

调用它

显然这不是 C 的工作方式,但我想了解如何 (以及为什么我的代码因顶部大小损坏而崩溃)

错误是这一行:

char * returnVal = malloc(sizeof(input));

它是一个错误的原因是它请求足够大的分配 space 来存储指针,这意味着 64 位程序中的 8 个字节。您要做的是分配足够的 space 来存储修改后的字符串,您可以使用以下行:

char *returnVal = malloc(strlen(input) + 1);

所以你问题的另一部分是为什么当你的字符串少于 26 个字符时程序不会崩溃。原因是允许 malloc 给调用者比调用者请求的多一些。

在您的情况下,消息“malloc(): corrupted top size”表明您正在使用 libc malloc,这是 Linux 上的默认设置。在 64 位进程中,malloc 的变体将始终为您提供至少 0x18 (24) 字节(最小块大小 0x20 - size/status 的 8 字节)。在分配紧接在“顶部”分配之前的特定情况下,超过分配末尾的写入将破坏“顶部”大小。

如果您的字符串大于 23 (0x17),您将开始破坏后续分配的 size/status,因为您还需要 1 个字节来存储尾随 NULL。但是,任何 23 个字符或更短的字符串都不会造成问题。

至于为什么您没有收到带有 26 个字符的字符串的错误,要回答这个问题,您必须查看带有 26 个字符的字符串的确切程序,该程序不会崩溃才能给出更准确的答案。例如,如果程序提供一个包含 3 个空格的 26 个字符的输入,这将只需要分配 26 + 1 - 3 = 24 个字节,这将适合。

如果您对那种程度的细节不感兴趣,修复 malloc 调用以请求适当的数量将解决您的崩溃问题。