C - 连接字符串

3
尝试使用C语言连接字符串(*char)时,遇到了许多分段错误:
void printDateFormat( char *in ) { /* begin function printDateFormat */

   char *month;          // month by char
   int month_int;        // month by digit
   char *day;            // day by char
   char *year;           // year by char
   char *dateToken;      // date token in split
   char *formatted;      // formatted string

   dateToken = strtok (in, "/");
   month = &dateToken;

   formatted = formatted = getMonth(month);

   dateToken = strtok (NULL, "/");
   day = &dateToken;

   formatted = strcat (formatted, day);
   formatted = strcat (formatted, ", ");

   dateToken = strtok (NULL, "/");
   year = &dateToken;

   formatted = strcat (formatted, year);

   in = *formatted;

} /* End function printDateFormat */


char *getMonth( int d) { /* begin function *getMonth */

switch (d) {

  case 1:
     return "January";
 //    break;
  case 2:
     return "February";
 //    break;
  case 3:
     return "March";
 //    break;
  case 4:
     return "April";
//     break;
  case 5:
     return "May";
//     break;
  case 6:
     return "June";
//     break;
  case 7:
     return "July";
//     break;
  case 8:
     return "August";
//     break;
  case 9:
     return "September";
//     break;
  case 10:
     return "October";
 //    break;
  case 11:
     return "November";
//     break;
  case 12:
     return "December";
//     break;
   }

} /* End function *getMonth */

输入到printDateFormat()函数中的值应该是另一个字符串,格式为:MM/dd/yyyy ... 例如 03/31/2013。目的是将其转换成:March 31, 2013。

编辑:

以下是我传递给printDateFormat函数的方式:

void option1( void ) { /* begin function option1 */

    char date[10]; /*user input date string */

    printf("\n\nEnter date [Format: MM/dd/yyyy]: ");
    fgets(date, 10, stdin);

    scanf("%s", &date);

    printDateFormat(date);

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

} /* End function option2 */

编辑2:

好的,我做了一些更改,但还是不行...

这里是我的编译器警告:

asgn9.c: In function `printDateFormat':
asgn9.c:224: warning: passing arg 1 of `getMonth' makes integer from pointer without a cast
asgn9.c:237: warning: assignment makes pointer from integer without a cast

他们指的是在我的printDateFormat()中使用getMonth()

这是我的更新代码,但我仍然在同一位置得到分段错误...

void printDateFormat( char *in ) { /* begin function printDateFormat */

    char *month;          // month by char
    int month_int;        // month by digit
    char *day;            // day by char
    char *year;           // year by char
    char *dateTkn;      // date token in split
    char *formatted;      // formatted string

    dateTkn = strtok (in, "/");
    month = dateTkn;

    formatted = getMonth(month);

    dateTkn = strtok (NULL, "/");
    day = dateTkn;

    formatted = strcat (formatted, day);
    formatted = strcat (formatted, ", ");

    dateTkn = strtok (NULL, "/");
    year = dateTkn;

    formatted = strcat (formatted, year);

    in = *formatted;

} /* End function printDateFormat */

char *getMonth( int d) { /* begin function *getMonth */

    static char *months[] = {"January", "February", "March", "April", "May",
        "June", "July", "August", "September", "October", "November", "December"};

    return strcpy(malloc(32), months[d]);

} /* End function *getMonth */

1
你要传递什么给 printDateFormat 函数? - Sergey Kalinichenko
1
scanf("%s", &/*<<== Here*/date); 中,您不需要使用“&”符号,这与 scanf("%s", date); 一样好。 - Sergey Kalinichenko
1
对于 getMonth() 函数,可以这样实现:char *months[] = { "January", "February, ... }; char *getMonth(int d) { return strcpy(malloc(50), months[d]); } - DigitalRoss
1
@DigitalRoss 这是违反封装、抽象和软件设计的所有原则的方式。 - Jim Balter
1
char *in ... in = *formatted -- 这只会复制字符串的第一个字符。 - Jim Balter
哎呀,实际上情况比那更糟糕...它会将字符串的第一个字符复制到指针中;如果你随后对指针进行解引用,将会出现未定义的行为。你需要使用 char** in ... *in = formatted ... 更好的方法是,直接返回 formatted 而不是通过参数来存储它。你还应该以高级警告级别编译...编译器应该警告 in = *formatted; 的问题。 - Jim Balter
6个回答

4
你的 getMonth 函数返回一个指向字符串文字的指针。尝试修改它(例如使用 strcat)是不允许的--这会导致未定义的行为。
我(强烈)建议使用 strftime 来处理格式化日期和/或时间字符串以进行打印。这不仅将减少你的格式化代码到一行,而且还可以支持本地化结果(如果你需要的话)。
编辑:如果你不能使用 strftime,你将想要在自己的缓冲区中构建一个格式化的日期,可能使用 sprintf
char buffer[256];
static const char *months[] = {
    "January", 
    "February", 
    /* ... */ , 
    "November", 
    "December"
};

sprintf(buffer, "%s %d %d", months[monthnum], day, year);

这是关于编程的内容。我们需要将其从英语翻译成中文。只需返回已翻译的文本即可,不要进行解释:这是为了一个项目,我们被指示自己处理转换...所以不能使用strftime。 - SnakeDoc
1
@SnakeDoc,但你是否理解了杰里第一个段落的要点?C语言中没有其他编程语言中那样神奇的东西;如果你要使用“strcat”复制字节,你需要为它们腾出空间,并且在字符串常量后面没有空间。 - Jim Balter
@JimBalter我已经发布了一个编辑,展示了我的修改后的代码,但是我仍然收到了分段错误的提示。似乎我在formatted = getMonth(month);这一行上有些问题,因为如果我添加一个printf并显示“month”,它就会显示正确,但是如果我在上述行之后添加一个printf来显示“formatted”,则会出现分段错误。 - SnakeDoc
太好了,谢谢!我已经移除了 getMonth() 并在 printDateFormat() 中使用了 sprintf。谢谢! - SnakeDoc

1
你还没有为formatted分配任何内存。将formatted的声明更改为 char formatted[80]; 并将第一个赋值改为formatted strcpy ( formatted, getMonth ( month ), sizeof ( getMonth ( month ) ) ); 这样就可以了。

1

C不是一个处理字符串的语言。如果可能的话,请使用C++和std::string。

在C中实现这个功能的一种方法是定义一个大的char buffer[BUFFERSIZE]缓冲区,将两个字符串复制到其中以便连接。要小心不要超过缓冲区的大小!

您也可以使用malloc/free函数分配/释放缓冲区,但那会带来另一堆问题。


1

返回的值为

getMonth(month);

指向一个常量字符串。您无法修改此字符串,包括strcat()。您可以更改函数以满足您的要求,如下:

char formatted[MAXSIZE];      // formatted string
getMonth(month, formatted);

void getMonth( int d, char *cache) { /* begin function *getMonth */
    switch (d) {
        case 1:
            strcpy(cache, "January");
            return;
        ......
}

之后,您可以继续修改字符数组“formatted”中的内容。

是的,这段代码只是演示了这个想法。它没有进行任何错误检查或安全检查。 - Sheng
1
是的,但新手常常采用这些答案,养成不良习惯,成为专业程序员,编写大量易受攻击的代码,我们已经见识到了结果。 - Jim Balter
1
抱歉,我是一个新手。我会在接下来的回答中考虑安全问题。感谢您的提醒。 - Sheng
1
不需要道歉。很多其他答案也是这样的,包括在这个页面上。谢谢你关注我并关心这个问题。:-) - Jim Balter

1
假设您的帖子是正确的,那么问题就是:
month = &dateToken;
....
day = &dateToken;
....
year = &dateToken;

strtok返回char*,因此只需从每个“dateToken”中删除&。 而你的“getMonth”输入原型是“int”类型,但你给出的函数是“char *”类型, 'switch'表将无法识别非数字表格情况。


1
你可以通过以下方式解决一些问题并简化代码:
char *getMonth(int d) {
  static char *months[] = { "January", "February", "March",
    . . .
  };

  return strcpy(malloc(60), months[d]);
}

这样做的好处是:

  • 返回值是可写的
  • 它有额外的空间供您进行strcat()操作

如果需要工业级别的稳定性,你可能需要检查malloc()的返回值,查看n是否在范围内等等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接