C 语言里如何给从键盘输出获得字符串动态分配内存 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xjr1022
V2EX    C

C 语言里如何给从键盘输出获得字符串动态分配内存

  •  1
     
  •   xjr1022 2018-12-07 00:53:24 +08:00 3096 次点击
    这是一个创建于 2553 天前的主题,其中的信息可能已经有所发展或是发生改变。

    关于动态分配内存,我看到的一个回答感觉太麻烦,该回答传送门

    https://segmentfault.com/a/1190000007675747

    于是我尝试用 realloc 函数分配内存, 结果只要输出 6 个以上字符,程序就终止,原因搜了半天没找到,难道只能一开始就给字符串分配足够大的空间吗 (菜鸟一枚,才学 C 没几天求大神轻喷)

    #include <stdlib.h> #include<string.h> void main() { char str[6]; char *new_str = str; //输入 6 个以上的字符 scanf("%s", str); if (strlen(str)>sizeof str) { new_str = (char*)realloc(str, 100*sizeof(char)); } prin return 0; } 
    第 1 条附言    2018-12-07 01:26:01 +08:00
    忘记说一个重点了,因为异常的地方是在 main 函数结尾处异常,所以我想着在函数结束点能不能修补这个越界,才会有这种想法。。
    第 2 条附言    2018-12-07 01:31:06 +08:00
    又发现传送门也放错了,更正下
    https://segmentfault.com/a/1190000000360944
    第 3 条附言    2018-12-07 01:57:49 +08:00
    看来也只能用这两种方法了,C 的内存管理确实是真的麻烦。。。
    ```c
    char * getline(void) {
    char * line = malloc(100), * linep = line;
    size_t lenmax = 100, len = lenmax;
    int c;

    if(line == NULL)
    return NULL;

    for(;;) {
    c = fgetc(stdin);
    if(c == EOF)
    break;

    if(--len == 0) {
    len = lenmax;
    char * linen = realloc(linep, lenmax *= 2);

    if(linen == NULL) {
    free(linep);
    return NULL;
    }
    line = linen + (line - linep);
    linep = linen;
    }

    if((*line++ = c) == '\n')
    break;
    }
    *line = '\0';
    return linep;
    }
    ```

    ```c
    char* getstr()
    {
    char* str;
    char* _str;
    int i = 1;
    str = (char*)malloc(sizeof(char) * (i + 1));
    while('\n' != (str[i - 1] = getchar()))
    {
    i ++;
    _str = (char*)malloc(strlen(str) + 1);
    str[i - 1] = '\0';
    strcpy(_str, str);
    free(str);
    str = (char*)malloc(sizeof(char) * (i + 1));
    if(NULL == str)
    {
    free(_str);
    printf("No enough memory!");
    return NULL;
    }
    strcpy(str, _str);
    free(_str);
    }
    str[i - 1] = '\0';
    return str;
    }
    ```
    19 条回复    2018-12-07 17:12:23 +08:00
    msg7086
        1
    msg7086  
       2018-12-07 01:04:21 +08:00
    > 难道只能一开始就给字符串分配足够大的空间吗

    当然了。

    类比一下。旅行团定酒店,起手先定 3 间双人房,然后来了个 20 个人的团,你说会发生什么事呢。
    xjr1022
        2
    xjr1022  
    OP
       2018-12-07 01:05:24 +08:00
    更正一下,prin 是 printf("%s",new_str);
    xjr1022
        3
    xjr1022  
    OP
       2018-12-07 01:07:28 +08:00
    @msg7086 就是为了避免这种越界溢出情况,我想着用 realloc 来改增大空间,然后就程序异常。。。
    nccer
        4
    nccer  
       2018-12-07 01:11:06 +08:00
    @xjr1022 你应该在 6 个字符的时候增大空间,大于 6 的判断条件已经越界了。
    msg7086
        5
    msg7086  
       2018-12-07 01:11:58 +08:00   1
    @xjr1022 越界发生在增大空间之前。程序都炸穿了你稍后再增大空间还有什么用呢。
    就像这 20 个人的团在酒店大堂睡了一晚以后,第二天你再去定其他 7 个房间……
    kokutou
        6
    kokutou  
       2018-12-07 01:20:11 +08:00   1
    起手一个 char *str = malloc(1000 * sizeof(char));
    输入超过 1000 就再改大点。
    tomychen
        7
    tomychen  
       2018-12-07 01:21:31 +08:00   1
    你已经越界在先了
    anonymous256
        8
    anonymous256  
       2018-12-07 01:26:10 +08:00 via Android   1
    char str[6]; //你声明它的上限是 6
    scanf 在读取时会检查是否溢出。

    你可以用 gets 或 fgets(更安全)
    int main()
    {
    char string [256];
    fgets (string, 256, stdin);
    printf ("%s\n",string);
    return 0;
    }
    参考:http://c.biancheng.net/cpp/html/260.html
    xjr1022
        9
    xjr1022  
    OP
       2018-12-07 01:27:12 +08:00
    @msg7086 忘记说了,因为异常是发生在 main 函数结尾出,所以才想出这种方法能不能事后补救,不过看来是没救了,
    tomychen
        10
    tomychen  
       2018-12-07 01:47:55 +08:00
    如果是真的有需要遇到不定长度,就得需要对每次输入处理了,如果只是学习的话,也就是楼上说的定个 256 或者 1024, 用 fgets 或者其他安全函数,也只是把超出的给截掉,而不是动态扩充。

    还有 char *argv[]是个好东西
    xjr1022
        11
    xjr1022  
    OP
       2018-12-07 01:54:01 08:00
    @tomychen 我也就是学习下,突发奇想,看来也只能这样了,谢谢啦
    msg7086
        12
    msg7086  
       2018-12-07 01:55:54 +08:00   1
    @xjr1022 异常发生在结尾是因为,不是不报,时候未到。
    还是拿旅行团做例子。那 20 个人的团有可能当场就来揍你了(比如复写了保护内存,直接 SEGFAULT ),也有可能等回家了以后把你告上法庭(比如复写得不多,直到程序退出清算内存空间的时候才发现内存乱套了)。
    xjr1022
        13
    xjr1022  
    OP
       2018-12-07 01:59:55 +08:00
    @msg7086 嗯嗯,是的,也是突发奇想,看来还是骗不了编译器~,果然还是得老老实实得按照传送门里得那种方法才行,谢谢辛苦回复啦 (●''●)
    xjr1022
        14
    xjr1022  
    OP
       2018-12-07 02:01:12 +08:00
    @nccer 这就又回到了我传送门里得那种方法了,还是得老老实实得写,骗不了编译器~
    tomychen
        15
    tomychen  
       2018-12-07 02:20:26 +08:00
    你可以放弃 scanf,当然 很多 C 语言的书里一直在强调这个函数,其实这是个很鸡肋的函数

    真要可变简单点就是
    int main(int argc, char *argv[]){
    //process argv
    }
    然后 就是 getopt()

    至于 scanf(),你可以用了 argv 和 getopt 忘了那个它
    maokabc
        16
    maokabc  
       2018-12-07 02:40:12 +08:00 via Android   1
    char str[6];分配在栈上,哪能用 realloc 扩容?
    geelaw
        17
    geelaw  
       2018-12-07 02:42:59 +08:00 via iPhone   1
    @xjr1022 #13 你这个想法是不对的。编译器可以完全不 care 你“骗没骗”它,在你违反标准里的一些规定的时候,受苦的是你自己的程序,而不是编译器因为你的程序有了未定义行为,它的功能不再有保障。
    kljsandjb
        18
    kljsandjb  
       2018-12-07 08:21:14 +08:00 via iPhone
    man realloc 先
    rochek
        19
    rochek  
       2018-12-07 17:12:23 +08:00   1
    其实,这个地方如果一定要用动态申请内存,是可以做到的
    挂钩一下输入函数,重写将输入放进内存的代码

    每次放进内存,都 malloc 空间
    或者,每次都 realloc 内存

    在这段内存用完之后,手动释放下

    但是会很麻烦,不如不做
    简单的做法就是一开始就申请足够的内存空间
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5241 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 01:25 PVG 09:25 LAX 17:25 JFK 20:25
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86