【问题标题】:Dynamic string allocation in cc中的动态字符串分配
【发布时间】:2017-11-11 23:30:38
【问题描述】:

我遇到问题的函数是我在下面创建的,DynamicString。 该函数旨在创建一个可变大小的字符串。

void DynamicString(char **txt)
{
    int i;
    int n = 0; //number of characters
    char c;
    *txt = (char *)malloc(1);//one byte of memory for the terminator
    (*txt)[0] = '0'; // termination charcter is the first point
    char *tmp = NULL; //temporary pointer

    scanf("%c", &c);
    while(c != '\n')//while true input
    {

        tmp = (char*)malloc(n+2);//allocates memory for incoming charcter and termination point
        for (i=0; i < n; ++i)//doesn't copy over an empty list
        {tmp[i] = (*txt)[i];}

        tmp[n] = c; //inputs character in releveant position
        tmp[n+1] = '0'; //places term. point
        ++n;// incriments the number of charcters(not including 0
        scanf("%c", &c);
    }

    free(*txt);//frees old mem
    *txt = tmp;// txt points to tmp
    printf("\nThe entered string is : %s",*txt);


    return;
}

void Frequency(char *s, int *array)
{
    int i;
    for(i=0; s[i] != '\0'; i++)//counts the frequncies of each character
    {
        array[s[i]]++;
    }
    /* Print characters and their frequency */

    return;
}

int main()
{
    //int Freq[128] = {0};// frequency of characters
    char * string;
    DynamicString(&string);

    free(string);

    return 0;
}

如果有人可以修复我已经创建的代码,那将非常有帮助。我知道可能有更好的算法,但我只想知道我做错了什么。谢谢!

【问题讨论】:

  • 代码看起来很奇怪,问题之一是字符串终止符号不正确。它应该是“\0”,而不是“0”。
  • 我认为你所有的'0' 字符都应该是'\0',这是完全不同的。 (我看到两个'0' 实例和一个'\0' 实例)
  • 遗憾的是没有变化
  • 问题是我没有在 while 循环中复制 tmp 字符串。

标签: c


【解决方案1】:

首先,正如其他人指出的那样,正确的字符串结尾是'\0',这是一个终止NUL 字符。

其次,如果读取的第一个字符恰好是换行符,则永远不会执行循环。在你 free(*txt); *txt 指向 tmp 之后,这是一个 NULL,所以你不能使用 printf("\nThe entered string is : %s",*txt); 因为你正在取消引用 NULL 指针,它是 c 中的 未定义行为。

第三,你有一个内存泄漏,因为在循环中你使用malloc()分配内存给tmp,每次都会给你一个新的内存地址。这意味着在循环中的每个循环中,tmp 都会有一个新地址,而您会丢失旧地址并且无法再释放它。

如果您想增加或减少指针指向的内存大小,请使用realloc。如何使用realloc 的一个非常简单的示例就像

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


int main(void)
{
    int initalSize = 10;
    int increasedSize = 20;

    /*
     *  Because temp type is char, I left sizeof operator out. you can always write like
     *  char *sentence = malloc(initialSize * sizeof(*sentence)); or
     *  char *sentence = malloc(initialSize * sizeof(char));
     */
    char *sentence = malloc(initalSize);
    char *temp = NULL;

    /* 
     * Malloc can return a NULL pointer. You need to check sentence value before using it
     * elswhere in the code.
     */
    if (!sentence) {
      printf("Memory allocation failed for sentence\n");
      exit(EXIT_FAILURE);
    }

    // Some code here...

    /*
     * Realloc can also return a NULL pointer. Need to use a temporary
     * pointer. In case realloc really returns NULL, and you don't use a temporary pointer and
     * use it like "sentence = realloc(sentence, increasedSize);", you will have a memory leak
     * because now sentence = NULL and you don't have a pointer that points to the old memory.
     *
     */
    temp = realloc(sentence, increasedSize);

    // Also need to check temporary pointer value.
    if (!temp) {
      printf("Allocating more memory to sentence failed\n");

      // One of the possible solutions. You can always use the value that you already have in sentence;
      free(sentence);
      exit(EXIT_FAILURE);
    }

    /*
     * If everything was ok, you make sentence point to the same address in memory as temp was pointing.
     * What it means is that you give ownership of the memory temp points to the sentence.
     */
    sentence = temp;

    // Some code here...


    // No need for sentence anymore
    free(sentence);

    /*
     * It is always recomended to make unused pointers that you don't use anymore or if you have
     * freed them to point to NULL;
     * It makes sure that those pointers no longer point to the previous memory addresses. Remember that
     * free only frees the memory where sentence and temp pointed to.
     *
     * If you don't make them point to NULL, then sentence and temp would be called a dangling pointer.
     *
     */
    sentence = NULL;
    temp = NULL;

    // Some code here...

    return 0;
}

如果您使用 Linux,最好使用名为 Valgrind 的程序检查您的代码。它有助于检测内存泄漏和内存错误。

此外,要从stdin 读取字符,我会使用getchar()。它更简单,更快。 Stack Overflow 回答 here 中的一个小信息。

最后一点,如果你使用一个什么都不返回的函数,你不需要在函数末尾写return。

【讨论】:

    猜你喜欢
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    • 2018-01-29
    • 1970-01-01
    • 2015-07-14
    • 2011-10-21
    • 1970-01-01
    相关资源
    最近更新 更多