【问题标题】:Sprintf Segmentation FaultSprintf 分段错误
【发布时间】:2011-11-03 07:06:06
【问题描述】:

numCheck 是 1-1000 之间的数字。仅当我在 charcheck 中收集 sprintf 的结果时,此代码才会给我一个段错误。如果我只使用 sprintf 而不使用结果,则不会出现段错误。这里发生了什么?

char * numString;
int charcheck = sprintf(numString, "%d", numCheck);

【问题讨论】:

    标签: c segmentation-fault printf


    【解决方案1】:

    最直接的做法是使用上面的数组,例如,

    char numString[80] = { };
    

    由 Seth、Jesus 和 Kerrek 建议。

    我认为 sth 的最后一个答案是一个很好的解释:“sprintf 的第一个参数应该指向 sprintf 应该写入格式化字符串的内存位置。”所以除了使用一个字符数组,这会强制为字符串分配内存,你还可以使用这个:

    char *numstring = (char*) malloc(80);
    

    这应该让您在不再需要时显式释放分配的内存。

    【讨论】:

      【解决方案2】:

      作为sprintf 的第一个参数给出的指针应该指向sprintf 应该写入格式化字符串的内存位置。

      在这种情况下,您没有初始化 numString 以指向您为格式化字符串分配的一些内存。由于numString 未初始化,它可能指向任何地方,在您的情况下,尝试将格式化输出写入该位置会导致分段错误。

      【讨论】:

        【解决方案3】:

        您需要为结果分配空间,例如

        char numString[50];
        int charcheck = sprintf(numString, "%d", numCheck);
        

        在您的情况下, sprintf 的内部工作正在尝试引用 NULL,这是您的情况下指针的默认值。

        【讨论】:

          【解决方案4】:

          sprintf 的第一个参数必须指向一个有效的缓冲区。你有一个char*,但它指向垃圾。

          将您的代码更改为:

          char numString[80] = { };
          int charcheck = sprintf(numString, "%d", numCheck);
          

          所以numString 实际上指向一个有效的缓冲区(在本例中为 80 个字符,所有元素都初始化为 0)。

          最好使用snprintf,这样您就可以将缓冲区的大小传递给它,这将有助于防止缓冲区溢出:

          const int bufsize = 80;
          char numString[bufsize] = { };
          int charcheck = snprintf(numString, bufsize - 1, "%d", numCheck);
          

          请注意,您从传递给snprintf 的缓冲区大小中减去一个,因为您不希望它使用最后一个槽,您要确保它是NULL 来表示字符串的结尾.

          【讨论】:

          • 有什么方法可以找出我在字符中传递的整数的大小,这样我就可以分配正确的空间量,而不是使用像 80 这样的任意值?
          • @user 仅分配额外空间可能会更有效(您可以通过存储它的类型计算出一个数字可以是的最大字符),因为计算它需要ifs 的级联。您只需计算您的数字小于的最大数字(例如,如果它小于 10(但总是> 0,请注意)它是 1 位数字,如果它小于 100 它是 2 位数字,等等)。但是在堆栈上分配空间需要恒定的时间(并且是一个非常小的常数),所以只要你不做类似char numString[9999999999999] 的事情,你应该没问题
          【解决方案5】:

          您需要为sprintf 提供自己的内存。另外,不要使用sprintf,而应使用snprintf

          char buf[1000] = {0};
          
          snprintf(buf, 999, ....);
          

          您也可以动态分配内存:

          char * buf = new char[BUFSIZE];
          snprintf(buf, BUFSIZE-1, ...);
          /* ... */
          delete[] buf;
          

          【讨论】:

          • 这是未定义的行为。有时未定义的行为完全符合您的预期,这可以说是最坏的情况。
          • 你为什么推荐snprintf而不是sprintf
          • @Kevin:你一般不知道sprintf会写多少个字符,所以一般不能正确使用,便携。即使您认为自己知道得更多,也最好不要破例,尤其是不要树立坏榜样。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多