在字符串连接中在程序中获取分段错误

时间:2017-04-25 19:58:30

标签: c c-strings

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

char *GetTodayDate()
{
   char *buffer;
   time_t t = time(NULL);
   struct tm tm = *localtime(&t);
   char monBuffer[3] ;
   char dayBuffer[3];
   char yearBuffer[5];

   sprintf(monBuffer, "%02d", tm.tm_mon + 1);
   sprintf(dayBuffer, "%02d", tm.tm_mday);
   sprintf(yearBuffer, "%d",  tm.tm_year + 1900);


   strcat(buffer, monBuffer);
   strcat(buffer, "/");
   strcat(buffer, dayBuffer);
   strcat(buffer, "/");
   strcat(buffer, yearBuffer);

   return buffer;
}

int main()
{
     char *today;
     sprintf(today,"%s",GetTodayDate());
     // I want to print the today string here to check, please give me proper statement here
     return 0;
}
  

我在程序中遇到分段错误,我想将dayBuffer,monBuffer,yearBuffer缓冲区存储到单个缓冲区中,这样我就可以将此缓冲区传递给另一个程序。我想将此缓冲区返回给另一个程序

3 个答案:

答案 0 :(得分:3)

你甚至没有分配buffer所以这是未定义的行为,写在未分配/随机区域。

char *buffer;

在这种情况下,可以安全地替换为

char *buffer = malloc(11); buffer[0]= '\0';

这是保持YYYY / MM / DD日期所需的大小,并初始化为0,因此第一个strcat正常工作(否则会出现另一种未定义行为的情况)

我会在一次sprintf调用中执行此操作,但没有所有临时缓冲区和strcat调用:

char *buffer = malloc(11); /* no need to initialize it beforehand */
sprintf(buffer, "%02d/%02d/%d", tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900);

(因为你返回 buffer,你不能使用char buffer[11];,即使它很有吸引力,因为范围仅限于当前例程)

除此之外:main()中的同一问题。你是(再次)写在未定义的内存中。既然你分配了内存就行了:

int main()
{
     char *today = GetTodayDate();
     printf("The date is %s\n",today);
     free(today); // free memory, even if it's not really necessary here, you're quitting the program
     return 0;
}

答案 1 :(得分:3)

  

strcat(buffer,monBuffer);

您还没有为buffer分配任何内存,因此您会遇到段错误,因为buffer没有指向从堆分配的任何可写内存块来保存您的数据。使用malloc为您的字符串分配一些内存。并且不要忘记将这些内存返回到free这样的堆:

char *GetTodayDate()
{
    char *buffer = malloc (MAX_DT_STRING_LEN);
    /* ... */

    *buffer = 0;

然后在main()

char *today = GetTodayDate();

printf ("%s", today);
free (today);

优良作法是初始化指针并检查从malloc和其他可能分配内存的例程返回的值NULL

您也可以预先分配缓冲区并将指针传递给GetTodayDate()

此处MAX_DT_STRING_LEN是缓冲区的长度。为缓冲区选择任意合理的长度,以便能够保存最大可能的日期/时间字符串。

答案 2 :(得分:0)

正如其他人所指出的那样,你必须分配内存。那么问题就变成了#34;谁应该分配内存&#34;。请允许我提出三种相当标准的方式来回答这个问题及其缺点和优点。

一种可能性是让来电者分配内存 :(我还添加了错误报告,因为这是我比其他两个人更喜欢这种方法的原因之一,请随意忽略它。)

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

#define DATE_SIZE 12
enum error_codes {OK = 0, ERROR = -1};
// You could have multiple error codes

int GetTodayDate(char *buffer);

int main()
{
     char *today = malloc(DATE_SIZE);
     int err = GetTodayDate(today);
     if(err == OK)
         printf("Today is %s\n", today);
     else
         printf("Error getting date\n")
     free(today);
     return 0;
}

int GetTodayDate(char *buffer)
{
   /* Get the info */
   time_t t = time(NULL);
   struct tm tm = *localtime(&t);

   /* Convert it to strings */
   char monBuffer[3] ;
   char dayBuffer[3];
   char yearBuffer[5];
   sprintf(monBuffer, "%02d", tm.tm_mon + 1);
   sprintf(dayBuffer, "%02d", tm.tm_mday);
   sprintf(yearBuffer, "%d",  tm.tm_year + 1900);

   if( something_went_wrong_here)
        return -1;

   /* Put in the buffer */
   *buffer = '\0'; // same as doing buffer[0] = '\0'; but is more C-stylish
   strcat(buffer, monBuffer);
   strcat(buffer, "/");
   strcat(buffer, dayBuffer);
   strcat(buffer, "/");
   strcat(buffer, yearBuffer);

   return 0; // To indicate success, 
}

然后另一个选项,它不是THREAD SAFE但被许多C标准库函数使用,它将允许您调用函数返回字符串而不用担心内存管理如下:它使用 static函数GetTodayDate中的字符数组。这使得数组虽然充当局部变量,但在函数返回后仍然存在(静态局部变量实际上是一个只能在函数内访问的全局变量)。

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

#define DATE_SIZE 12

char *GetTodayDate();

int main()
{
     // Easier to use but has drawbacks
     printf("Today is %s", GetTodayDate());
     return 0;
}

char *GetTodayDate()
{
   /* Get the info */
   time_t t = time(NULL);
   struct tm tm = *localtime(&t);

   /* Convert it to strings */
   char monBuffer[3] ;
   char dayBuffer[3];
   char yearBuffer[5];
   sprintf(monBuffer, "%02d", tm.tm_mon + 1);
   sprintf(dayBuffer, "%02d", tm.tm_mday);
   sprintf(yearBuffer, "%d",  tm.tm_year + 1900);

   /* Put in the buffer */
   static char buffer[DATE_SIZE];
   buffer[0] = '\0';
   strcat(buffer, monBuffer);
   strcat(buffer, "/");
   strcat(buffer, dayBuffer);
   strcat(buffer, "/");
   strcat(buffer, yearBuffer);
   return buffer;
}

这也有一个缺点,如果你想在以后使用该值,你必须使用strcpy()复制它。但是你可以看到使用这个函数要简单得多。

第三个选项是让 GetTodayDate分配内存,这样做的好处是它知道要分配多少内存,从而使用户不必知道该细节。它的缺点是,由于客户端没有分配内存,他可能有更多机会忘记释放内存。

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

#define DATE_SIZE 12

int GetTodayDate(char *buffer);

int main()
{
     char *today = GetTodayDate();
     printf("Today is %s", today);
     // Easier to forget to do if 
     // we're not the one who wrote GetTodayDate
     free(today); 
     return 0;
}

char *GetTodayDate()
{
   /* Get the info */
   time_t t = time(NULL);
   struct tm tm = *localtime(&t);

   /* Convert it to strings */
   char monBuffer[3] ;
   char dayBuffer[3];
   char yearBuffer[5];
   sprintf(monBuffer, "%02d", tm.tm_mon + 1);
   sprintf(dayBuffer, "%02d", tm.tm_mday);
   sprintf(yearBuffer, "%d",  tm.tm_year + 1900);

   /* Put in the buffer */
   char *buffer = malloc(DATE_SIZE);
   buffer[0] = '\0';
   strcat(buffer, monBuffer);
   strcat(buffer, "/");
   strcat(buffer, dayBuffer);
   strcat(buffer, "/");
   strcat(buffer, yearBuffer);

   return buffer;
}

我个人更喜欢第一个,因为它允许我使用返回值进行错误报告。此外,许多C标准库函数都以这种方式工作:调用函数并告诉它(通过参数)将您请求的信息放在何处。当您希望函数在不复制的情况下返回多个内容时,这尤其有用。

struct BigStruct bs;
// get me this info and here's 
// where you're going to put said info.
if(get_BigStruct(&bs)){
     printf("could not get info\n");
     return ERROR;
}
printf("field1 %d\n", bs.field1);

但我离题了,关键是我最喜欢第一个因为 1)错误报告 2)分配和解除分配在同一地点完成 3)常见的C方式&#34;告诉我这些信息,以及您将要放置它的地方&#34;。