C中的字符数组是否有最大返回长度

时间:2017-08-13 05:53:45

标签: c arrays pointers

我正在尝试创建一个动态字符"字符串指针" / array并且我的代码不会打印值,输入的字符超过249个字符。我只是想知道字符数组/"字符串指针"是否有最大返回长度。

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

char *input() {
    char *inpt; 
    char check;
    int i;
    int count;

    i = 0;
    count = 1;
    check = '\0';

    inpt = (char*)malloc(1);

    while (check != '\n') {
        check = getchar(); 
        if (check == '\n') {
            break;
        } else {
            inpt[i] = check;
            i++;
            count++;
            inpt = realloc(inpt, count);
        }
    }
    inpt[i] = '\0';

    char *retrn;
    retrn = inpt;

    free(inpt);

    printf("%d \n", i);

    return retrn;
}

int main(int argc, char **argv) {
    char *name;
    printf("Please print name: \n");
    name = input();
    printf("%s is the name \n", name);
    return 0;
}

5 个答案:

答案 0 :(得分:4)

问题不在于您尝试返回的字符串的长度,而是返回指向不再分配给您的内存的指针:

char *retrn;
retrn = inpt;

free(inpt);

return retrn;

当你执行retrn = inpt时,你不会复制内存,而是有两个指针指向同一个内存。然后你free那个记忆并返回一个指向新自由记忆的指针。该指针当然不能被解除引用,任何这样做的尝试都会导致未定义的行为

解决方案不是retrn之类的任何临时变量,而是free函数中的input内存。而是返回inpt并在调用函数(在您的情况下为main)中free内存。

答案 1 :(得分:2)

这很可能是因为使用了空闲内存。您对retrn的分配输入不会创建另一个副本。您将获得未定义的行为,可能包括您正在经历的行为。

答案 2 :(得分:2)

继续我的评论,有许多方案可以动态分配内存。从效率的角度来看,你想要避免的一件事是不必要地为每个角色重新分配。不是为添加到名称的每个字符调用realloc,而是分配合理数量的字符来保存名称,如果达到该数量,则重新分配,将当前分配大小加倍,更新保持当前大小的变量并保持去。

您已有数组索引,因此无需单独保留count。只需使用您的数组索引作为计数器,确保您至少有index + 1个字符可用于为 nul-terminate inpt提供空间。

无需在input()中保留单独的指针。只需为inpt分配并在完成后返回inpt作为指向内存块的指针。 (不要忘记free (name);中的main(),这将释放您在input中分配的内存。

永远不要直接realloc指针。 (例如,不要inpt = realloc (inpt, size);)如果realloc失败,则返回NULL,导致丢失指向inpt之前引用的已分配块realloc的指针呼叫。而是使用临时指针,验证realloc是否成功,然后将新块分配给inpt(下面的示例)

完全放弃,你可以做类似的事情:

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

#define MEMSZ 32  /* initial allocation size (must be at least 1) */

char *input (void)
{
    char *inpt = NULL, check;
    size_t mem = MEMSZ, ndx = 0;

    if (!(inpt = malloc (mem))) {   /* allocate/validate  mem chars */
        fprintf (stderr, "input() error: virtual memory exhausted.\n");
        return NULL;
    }

    /* you must check for EOF in addition to '\n' */
    while ((check = getchar()) && check != '\n' && check != EOF) 
    {   /* check index + 1 to insure space to nul-terminate */
        if (ndx + 1 == mem) {       /* if mem limit reached realloc */
            void *tmp = realloc (inpt, mem * 2);    /* use tmp ptr */
            if (!tmp) {             /* validate reallocation */
                fprintf (stderr, "realloc(): memory exhausted.\n");
                break;      /* on failure, preserve existing chars */
            }
            inpt = tmp;     /* assign new block of memory to inpt */
            mem *= 2;       /* set mem to new allocaiton size */
        }
        inpt[ndx++] = check;    /* assign, increment index */
    }
    inpt[ndx] = 0;          /* nul-terminate */

    return inpt;            /* return pointer to allocated block */
}

int main (void)
{
    char *name = NULL;

    printf ("Please enter name: ");
    if (!(name = input()))  /* validate input() succeeded */
        return 1;

    printf ("You entered      : %s\n", name);
    free (name);    /* don't forget to free name */

    return 0;
}

示例使用/输出

$ ./bin/entername
Please enter name: George Charles Butte
You entered      : George Charles Butte

内存使用/错误检查

在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放

您必须使用内存错误检查程序,以确保您不会尝试在已分配的内存块的范围之外/之外进行写入,尝试读取或基于未初始化值的条件跳转,最后,确认您释放了已分配的所有内存。

对于Linux valgrind是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。

$ valgrind ./bin/entername
==2566== Memcheck, a memory error detector
==2566== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==2566== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==2566== Command: ./bin/entername
==2566==
Please enter name: George Charles Butte
You entered      : George Charles Butte
==2566==
==2566== HEAP SUMMARY:
==2566==     in use at exit: 0 bytes in 0 blocks
==2566==   total heap usage: 1 allocs, 1 frees, 32 bytes allocated
==2566==
==2566== All heap blocks were freed -- no leaks are possible
==2566==
==2566== For counts of detected and suppressed errors, rerun with: -v
==2566== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认已释放已分配的所有内存并且没有内存错误。

如果您有任何其他问题,请与我们联系。

答案 3 :(得分:1)

数组的大小存在内在限制:

  • 可用内存有限:malloc()如果由于缺少核心内存而无法履行请求,则realloc()可能会返回NULL。您一定要检查malloc()realloc()是否成功。
  • 系统配额可能会将进程可用的内存量限制为低于安装的实际物理内存或系统中可访问的虚拟内存的数量。
  • 数组的最大大小是size_t类型的最大值:SIZE_MAX,其最小值为65535,但您使用的类型为intmalloc()realloc()的请求,其范围可能小于size_t。在大多数当前桌面系统上,类型int是32位,其中size_t可能是64位,可用内存可能远远超过2GB。使用size_t代替int

但请注意,您的问题来自一个更简单的错误:您释放为字符串分配的内存块并返回指针的副本,该指针现在指向释放的内存。访问此内存具有未定义的行为,可以是任何内容,包括最多249个字节的明显正确行为和超出的故障。

另请注意,您应对int使用check类型,并将getchar()的返回值与EOF进行比较,以避免在输入不包含换行符时无限循环(例如空文件。)

以下是更正后的版本:

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

char *input(void) {
    char *p = malloc(1);  /* simplistic reallocation, 1 byte at a time */
    size_t i = 0;         /* use size_t for very large input */
    int c;                /* use int to detect EOF reliably */

    if (p == NULL) {
        return NULL;  /* allocation error */
    }
    while ((c = getchar()) != EOF && c != '\n') {
        char *newp = realloc(p, i + 2);
        if (newp == NULL) {
            free(p);   /* avoid a memory leak */
            return NULL;  /* reallocation error */
        }
        p = newp;
        p[i++] = c;
    }
    if (i == 0 && c == EOF) {
        free(p);
        return NULL;  /* end of file */
    }
    p[i] = '\0';
    return p;
}

int main(int argc, char **argv) {
    char *name;
    printf("Please print name: ");
    name = input();
    if (name == NULL) {
        printf("input() returned NULL\n");
    } else {
        printf("%s is the name\n", name);
        free(name);
    }
    return 0;
}

答案 4 :(得分:1)

  

C

中的字符数组是否有最大返回长度

字符数组的最大大小为SIZE_MAXSIZE_MAX至少为65535。

  

我只是想知道字符数组/“字符串指针”是否有最大返回长度。

对于字符串,其最大大小SIZE_MAX,最大长度SIZE_MAX - 1