首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在C中使用变量函数的字符串级联

在C中使用变量函数的字符串级联
EN

Stack Overflow用户
提问于 2014-10-06 09:35:11
回答 2查看 1.8K关注 0票数 3

我试着用C写一个基本的问答程序,它基本上会储存卡片和答案。但与此同时,我尝试使用我学到的新技术,如各种函数和动态内存分配。

当我改变常量时,我希望程序能够缩放,不应该像K&R所定义的那样有“神奇的数字”。问题是,我不能在fscanf的格式参数中使用变量。我需要手动定义字符串长度。为了克服这个限制,我尝试编写一个字符串级联函数,该函数将生成fscanf格式参数。

例如:

代码语言:javascript
复制
char * scanf_string = et_concat(5, "%", CARD_SIZE, "s | %", ANSWER_SIZE, "s");

常数定义为星座。

代码语言:javascript
复制
#define CARD_SIZE 200
#define ANSWER_SIZE 1000
#define CONCAT_SIZE 20

et_concat函数在etstring.h. h中。--这是分段错误发生的地方.

代码语言:javascript
复制
#include <stdarg.h>
#include <string.h>

char * et_concat (int count, char * str, ...)
{
    va_list ap;
    int j;
    char *concatted_string = (char *) malloc (count*CONCAT_SIZE+1);

    va_start(ap, str);
    for (j = 0; j < count; j++) {
        strcat(concatted_string, va_arg(ap, char *));
    }
    va_end(ap);

    return concatted_string;
}

我试图调用et_concat的代码在reader.c中。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "consts.h"
#include "etstring.h"

int iterate_inputs()
{
  char card[CARD_SIZE];
  char answer[ANSWER_SIZE];
  FILE *fp = fopen("data.txt","r");
  if (fp == NULL)
  {
    return EXIT_FAILURE;
  }
  char * scanf_string = et_concat(5, "%", CARD_SIZE, "s | %", ANSWER_SIZE, "s");
  printf(scanf_string);
  fscanf(fp, scanf_string, card, answer);
  printf("%s | %s\n", card, answer);
  fclose(fp);
  return EXIT_SUCCESS;
}

提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-10-06 10:13:30

您的级联例程有各种错误和缺点:

  • 您已经读取了非变量参数str中的第一个字符串,但您只打印了变量参数,其中只剩下4个。您实际上跳过了第一个字符串,而第五个字符串是垃圾。
  • 在分配字符串之后,您不会初始化它,这样它就可能包含垃圾。将第一个字符设置为'\0'就足以初始化以零结尾的空字符串.
  • 您分配了一个固定的缓冲区,而不是真正检查溢出。这有点违背直觉:要么分配一个缓冲区(以后必须释放),然后允许任意字符串长度,要么传递一个长度受限的缓冲区,而不关心例程中的分配。

还有一个问题是,你的论点并不都是字符串。一个简单的解决方案是使用strinfification macro。必须首先展开参数,以便字符串具有实际值,而不是宏的名称,这对scanf没有任何意义。此解决方案的问题是,在格式字符串中给定的大小不包括终止的'\0',因此您应该像这样分配缓冲区:

代码语言:javascript
复制
char card[CARD_SIZE + 1];

下面是您的实现的一个修正版本,它仍然不检查缓冲区溢出情况,不过:

代码语言:javascript
复制
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

#define CARD_SIZE 200
#define ANSWER_SIZE 1000
#define CONCAT_SIZE 20

char *et_concat(int count, ...)
{
    va_list ap;
    char *concatted_string = malloc(count * CONCAT_SIZE + 1);
    int j;

    *concatted_string = '\0';

    va_start(ap, count);
    for (j = 0; j < count; j++) {
        strcat(concatted_string, va_arg(ap, char *));
    }
    va_end(ap);

    return concatted_string;
}

#define STR1(X) #X
#define STR(X) STR1(X)

int main()
{
    char *scanf_string = et_concat(5, 
        "%", STR(CARD_SIZE), "s | %", STR(ANSWER_SIZE), "s");

    printf("'%s'\n", scanf_string);
    free(scanf_string);

    return 0;
}

编辑我在代码中编写了STR1(CARD_SIZE),而它应该是STR。现在修好了。

票数 4
EN

Stack Overflow用户

发布于 2014-10-06 09:51:30

有一种构造格式字符串的更简单的方法。因为“变量”是编译时常量,所以可以使用宏对它们进行字符串化,然后让编译器将它们连接起来。编译器将自动将相邻的字符串常量连接成单个字符串,例如。"this" "that" -> "thisthat".忏悔:我完全检查了https://stackoverflow.com/questions/2653214/stringification-of-a-macro-value得到这些(简单!?)宏可以正常工作。

代码语言:javascript
复制
$cat strfy.c
#define CARD_SIZE 200
#define ANSWER_SIZE 20
#define XSTR(x) STR(x)
#define STR(x) #x

printf("%" XSTR(CARD_SIZE) "s | %" XSTR(ANSWER_SIZE) "s", card, answer);

$cpp -P strfy.c
printf("%" "200" "s | %" "20" "s", card, answer);

正如M Oehm所指出的,为了将整数折叠成字符串,仍然需要这种带有变量函数的宏。否则,函数需要更加复杂才能处理不同类型的参数。

还有一种方法是使用sprintf构建格式字符串。但是这种方法有一个额外的复杂性,你需要预先计算字符串的大小。这个问题可以通过使用以snprintf作为目标字符串的NULL来解决,返回值将是所需的大小。

代码语言:javascript
复制
#define CARD_SIZE 200
#define ANSWER_SIZE 1000
#include <stdlib.h>
#include <stdio.h>

int main()
{
    char *fmt;
    size_t fmt_sz;
    char card[CARD_SIZE + 1];
    char answer[ANSWER_SIZE + 1];

    fmt = malloc(fmt_sz = snprintf(NULL, 0, "%%%ds | %%%ds", CARD_SIZE, ANSWER_SIZE) + 1);
    snprintf(fmt, fmt_sz, "%%%ds | %%%ds", CARD_SIZE, ANSWER_SIZE);
    //printf("%s", fmt);
    scanf(fmt, card, answer);

    return 0;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26213488

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档