【问题标题】:c strings, char pointers: need help printing the string and some advicec 字符串,字符指针:需要帮助打印字符串和一些建议
【发布时间】:2013-05-31 04:16:13
【问题描述】:

到目前为止我有这个代码:

char *str;
scanf ("%s", &str);
printf("%s",&str);
system("pause");

它可以工作,但问题是在我按下一个键继续程序(或结束它)后,我收到以下错误:

运行时检查失败 #2 - 变量“str”周围的堆栈已损坏。

我以前从来没有玩过 char 指针,我想解释一下为什么我会收到这个错误以及如何改进我从用户那里收到字符串输入的格式。我知道有更简单的方法,但我的最终目标是获得最简单的代码来确定输入的大小,而不是限制用户。

提前致谢

【问题讨论】:

    标签: c string pointers char scanf


    【解决方案1】:

    Printf 接受一个指针,而不是指针的地址。你应该这样使用它:

     scanf("%s", str)
     printf("%s", str);
    
    
    
     char * str = malloc(100);  //allocates 100 bytes
    
     scanf("%###c", str) //Gets line from STDIN. ### indicates how many to read MAXIMUM, so scanf("%2c", str) will read maximum 2 characters into str.  Don't use s, since then you read until every whiteline.
    
     int i = 0;
     while(str[i] != NULL){
    
     i++;    
    
     }
    
     realloc(buf, i+1); //make the string fit tightly. I'm unsure if it will be null     terminated
    

    //可能添加空终止 //你必须确保他们不会尝试

    【讨论】:

    • 这不起作用,我得到:运行时检查失败 #3 - 变量 'str' 正在使用而未初始化。我之前也尝试过,这是迄今为止对我有用的唯一变化。
    • 需要给str分配空间。 char * str = malloc(size of(whatsizedoyouwant));
    • 问题是我想要一个自定义大小的字符串。我想在用户输入后得到它的大小。
    • 如果空间不足,可以使用 realloc。这就是它在 C 中的工作方式。
    • 我没有办法分配我需要的确切大小吗?
    【解决方案2】:

    您正在扫描 str 而没有先为其分配内存。但是,幸运的是,它从一个随机地址开始存储,因此打印效果很好,但您的运行时系统识别出您遇到了一个您没有权限的内存区域。

    这里是解决方案:当它无法获得足够的连续内存时,这会导致realloc失败

     #include<stdio.h>
    #include<malloc.h>
    #define MAX 100
    int main(){
        char *str=malloc(sizeof(char)*MAX);
        int size=0;
        int capacity=MAX;
        char c;
        int i=0;
        while((c=getchar())!='\n'){
            if(size==MAX-1){
                capacity=2*MAX;
                realloc(str,capacity);
            }
            str[i]=c;
            i++;
        }
        str[i]='\0';
        printf("%s",str);
        system("pause");    
    }
    

    【讨论】:

    • 我应该提一下,它会打印字符串,就像我得到它一样,只有一个错误的输入。
    • @ziggyyoyo 我已经更新了错误原因,我将提供第二部分等待的解决方案
    • @ziggyyoyo 我们开始......看你也可以使用危险的gets 或使用循环组合更安全的fgets
    • 遇到了和 nicholaz 的建议一样的问题,@malloc, void* 不能用于初始化 char*
    • @ziggyyoyo 我已经测试了它工作的代码 :) 你可能错了....阅读这里*.com/questions/605845/… 几个小时前我在想你
    【解决方案3】:

    您的问题的第二部分(预先确定输入的长度)不可能使用简单的 scanf (除了变得更复杂和逐块读取/附加)。

    但至少下面的代码修复了您对随机内存的覆盖。

    char buffer[256];
    char *str= buffer;
    scanf ("%s", str);  // or scanf ("%s", buffer);  or scanf("%s", &buffer[0]);
    printf("%s", str);  // or printf("%s", buffer);  or printf("%s", &buffer[0]);
    system("pause");
    

    您可以事先使用一个非常大的缓冲区,然后将结果修剪回给定长度,但您需要最大值。开始的长度。

    char *str= (char *)calloc(1,10000);
    scanf ("%.9999s", str);
    str= (char *)realloc(str, strlen(str)+1);  // release excess memory 
    printf("%s", str); 
    free(str);
    system("pause");
    

    【讨论】:

    • 这个方法很简单,我知道怎么做。我正在寻找的东西是让缓冲区的大小与字符串减去分隔符的大小完全相同
    • ziggy:没有简单的方法可以做到这一点(在不知道多长时间的情况下获取字符串)。你需要提供一个最大可能的长度,然后也许你可以用结果的长度重新分配它
    • 而您的上述版本仅“有效”,因为您告诉系统将输入写入不属于您的内存中。运行时注意到它自己的一些内存正在被覆盖,这就是您收到错误消息的原因。
    • 那么你的问题也许可以从一个至少可以工作的版本开始,不要用明显错误的代码分散人们的注意力。
    • 我在我的帖子中提到它是错误的,因为我在这个特定领域没有经验。我已经说过,我的最终任务是或多或少地按照 magnisium 的建议去做。对不起,如果我做错了什么
    【解决方案4】:

    "my ultimate goal is to get the simplest code to determine the size of the input, and not limit the user."

    是的,问题就在这里,一旦你这样做,事情就会变得棘手。您不能简单地使用像这样的未初始化指针来获取“尽可能多”的字符。最简单的选项是:

    char *str = malloc(1000);
    scanf ("%999s", str);
    

    char str[1000];
    scanf ("%999s", &str);
    

    当然,这会限制输入的数量。 (顺便说一句:你真的应该评估是否有一个数字可以满足这个条件。)

    现在还有其他选择,但它们开始远离便携性。如果您使用的是 GCC,则可以使用“动态”规范:

    char *str;
    scanf("%ms", str); // dynamically allocate space for the size of input from the user
    

    但是现在使用它会将您的手与正在使用的编译器联系起来(也是版本,这适用于 c99,早期需要 "%as"

    除此之外,您可以一次读取 1 个字符的输入并将其附加到您自己增长的字符串中,但这是一个特定于操作系统的解决方案,因为您需要使用 ncursesgetch() 函数在 *nix 或 _kbhit()_getch(); 在windoze中。

    【讨论】:

    • 这里有人建议在我得到适合我目标的输入后重新分配。感谢您的意见。
    • @ziggyyoyo - 是的,这行得通,但请记住,从技术上讲,这种方法用户仍然受到输入大小的限制,realloc() 只会将缓冲区“缩小”回一个大小匹配输入的内容。
    • 其实是scanf("%ms", &amp;str)
    【解决方案5】:

    您已将str 声明为指针,但您尚未为其提供指向的有效位置;它最初包含一些随机值,可能是也可能不是可写的内存地址。您仍然需要分配一块足够大的内存来保存您的输入,方法是声明一个数组或使用malloccalloc 分配内存。

    其次,%s 转换说明符期望对应的参数具有char * 类型;由于str 具有该类型,因此您无需使用&amp; 运算符。

    所以,你需要做类似的事情

    char str[SOME_SIZE]; 
    

    char *str = malloc( SOME_SIZE );
    

    其中SOME_SIZE 大到足以容纳您输入的字符串加上一个额外的字符作为 0 终止符。

    您将按如下方式读取和写入输入:

    scanf( "%s", str ); 
    printf( "%s", str ); 
    

    您不需要&amp; 进行任何一次通话。 %s 转换说明符期望相应参数的类型为 char *。在大多数情况下1,数组类型的表达式被转换为指针类型的表达式,表达式的值是数组中第一个元素的地址。如果您将str 声明为一个数组,那么在scanfprintf 调用中,str2 将转换为char *。如果您将str 声明为char *,则它已经是预期的类型。

    现在,输出(通常)是行缓冲的,这意味着它不会显示在您的控制台上,除非有换行符或字符串的长度超过缓冲区长度。您要么想在打印语句中添加换行符:

    printf( "%s\n", str );
    

    或在标准输出流上调用fflush

    printf( "%s", str );
    fflush( stdout );
    

    以确保您的输出得到显示。


    1 - 当数组表达式是sizeof 的操作数时,会出现此规则的例外情况。 _Alignof 或一元 &amp; 运算符,或者是用于在声明中初始化另一个数组的字符串文字。

    2 - 请记住,此转换操作适用于 表达式,而不适用于对象。您偶尔会听到有人声称“数组是指针”,但这不是真的;数组和指针完全是不同的动物。

    【讨论】:

      最近更新 更多