首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
拉勾
V2EX  ›  C/C++/Obj-C

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

  •  1
     
  •   xjr1022 · 11 天前 · 870 次点击

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

    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 条附言  ·  11 天前
    忘记说一个重点了,因为异常的地方是在 main 函数结尾处异常,所以我想着在函数结束点能不能修补这个越界,才会有这种想法。。
    第 2 条附言  ·  11 天前
    又发现传送门也放错了,更正下
    https://segmentfault.com/a/1190000000360944
    第 3 条附言  ·  11 天前
    看来也只能用这两种方法了,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
        1
    msg7086   11 天前
    > 难道只能一开始就给字符串分配足够大的空间吗

    当然了。

    类比一下。旅行团定酒店,起手先定 3 间双人房,然后来了个 20 个人的团,你说会发生什么事呢。
        2
    xjr1022   11 天前
    更正一下,prin 是 printf("%s",new_str);
        3
    xjr1022   11 天前
    @msg7086 就是为了避免这种越界溢出情况,我想着用 realloc 来改增大空间,然后就程序异常。。。
        4
    nccer   11 天前
    @xjr1022 你应该在 6 个字符的时候增大空间,大于 6 的判断条件已经越界了。
        5
    msg7086   11 天前   ♥ 1
    @xjr1022 越界发生在增大空间之前。程序都炸穿了你稍后再增大空间还有什么用呢。
    就像这 20 个人的团在酒店大堂睡了一晚以后,第二天你再去定其他 7 个房间……
        6
    kokutou   11 天前   ♥ 1
    起手一个 char *str = malloc(1000 * sizeof(char));
    输入超过 1000 就再改大点。
        7
    tomychen   11 天前   ♥ 1
    你已经越界在先了
        8
    anonymous256   11 天前 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
        9
    xjr1022   11 天前
    @msg7086 忘记说了,因为异常是发生在 main 函数结尾出,所以才想出这种方法能不能事后补救,不过看来是没救了,
        10
    tomychen   11 天前
    如果是真的有需要遇到不定长度,就得需要对每次输入处理了,如果只是学习的话,也就是楼上说的定个 256 或者 1024, 用 fgets 或者其他安全函数,也只是把超出的给截掉,而不是动态扩充。

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

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

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

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

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

    但是会很麻烦,不如不做
    简单的做法就是一开始就申请足够的内存空间
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   812 人在线   最高记录 4019   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.1 · 20ms · UTC 19:41 · PVG 03:41 · LAX 11:41 · JFK 14:41
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1