在c-扩展,替换,存储和打印字符串中使用字符串

时间:2018-06-01 01:21:21

标签: c arrays string

我有一个简单的C程序,它应该根据以下规则扩展字符串FX

X -> X+YF+
Y-> -FX-Y

该计划如下:

#include <stdio.h>
void expandOnce( )
{
     char* s = (char*)malloc(sizeof(char)*100);
     int i=0;
     char str[]="FX";
     while(str[i]!='\0')
     {
           if(str[i]=='X')
           {
               s[i]="X+YF+";
           }
             if(str[i]=='Y')
           {
               s[i]="-FX-Y";
           }
           i++;
     }
          printf("%s",s);
}


void expandNtimes (int n)
{

for (int i =0; i < n; i++){
expandOnce();
}

}
int main(){
   expandNtimes(2);
    return 0;
}

如果程序正确执行,则应打印出来:

  FX+YF++-FX-YF+

这是在使用上述规则进行2次FX扩展之后。 问题:  1.如何在不打印乱码的情况下完成这项工作?  2.如何从expandNtimes()和expandOnce()返回展开的数组,以便我可以在main函数中使用它?

我试试这个,但我一直在记忆错误。

根据您的建议,我做了以下更改:

#include <stdio.h>
#include <string.h>
#define NTIMES  2
#define MAXC  100

void expandOnce( )
{
    char s[MAXC];
     int i=0;
     s[0]='F';
     s[1]='X';

     while(s[i]!='\0')
     {
    if(s[i]=='X'){
    //shift all letters to the right by 5 steps
        for (i; i < MAXC; i++){ //warning: statement with no effect (Wunused value)
            s[i + 5]= s[i];
            if(s[i]=='\0'){
            break;}
                  }
    //Fill in the expansion
        s[i]='X';
        s[i+1] ='+';
        s[i+2] ='Y';
        s[i+3]='F';
        s[i+4] ='+';
    }
  if(s[i]=='Y'){
  //shift all letters to the right by 5 steps
        for (i; i < MAXC; i++){ //warning: statement with no effect (Wunused value)
            s[i + 5]=s[i];
            if(s[i]=='\0'){
            break;}
                }
    //Fill in the expansion
        s[i]='-';
        s[i+1] ='F';
        s[i+2] ='X';
        s[i+3]='-';
        s[i+4] ='Y';
    }
             i++;
     }
          printf("%s\n",s);
           printf("Me\n");
}


void expandNtimes (int n)
{

for (int i =0; i < n; i++){
expandOnce();
}

}
int main(){
expandOnce();
expandNtimes(NTIMES);
return 0;
}

我的两个for循环都有一个我不明白的警告warning: statement with no effect (Wunused value)。最后,我收到了这个错误:

Segmentation fault (core dumped)

是否允许在while循环中执行for循环?

2 个答案:

答案 0 :(得分:2)

哦,男孩......你的代码中是否有一份“你不能那样做......”的完整清单。

首先,不需要强制转换malloc,这是不必要的。请参阅:Do I cast the result of malloc?

char *s = malloc (sizeof *s * 100);

就是所需要的(注意:如果你总是使用sizeof dereference_pointer,你的版本大小总是正确的。

这提出了另一点,如果你需要常量#define一个(或更多)或使用全局enum来完成同样的事情,例如。

#define NTIMES  2
#define MAXC  100

enum { NTIMES = 2, MAXC = 100 };

然后你可以使用它们,

char *s = malloc (sizeof *s * MAXC);

expandNtimes(NTIMES);

通过定义常量,您可以在代码顶部有一个方便的位置,以便在将来需要时进行更改,而不必选择每个分配或函数调用来更改所有硬编码的幻数

您的记忆泄漏

您在s中分配expandOnce,但从不free s,并且不会返回指针,以便稍后可以在main()中释放它(或任何其他呼叫功能)。

您应该在free (s);之后添加printf("%s",s);(您还应该包含newline以防止多个输出一起运行,并且您的程序符合POSIX标准 - 输出最终'\n'),例如printf("%s\n",s);

此外,“为什么还要动态分配?”只需使用固定缓冲区,您就不会尝试返回它。只需使用:

char s[MAXC] = "";

s未初始化且您离开s[0]未初始化

s[i]="X+YF+";s[i]="-FX-Y";从索引s1写入4个字符。永远不会初始化s[0],导致后续尝试从s读取未定义行为。您不能简单地将指向字符串文字 "X+YF+";的指针分配给字符s[i] - 您的编译器应该尖叫警告和错误。< / p>

您可以使用以下内容将文字复制到s

strcpy (s, "X+YF+");

或者你可以随便循环重复复制,例如

int i;
for (i = 0; str[i]; i++) /* loop over each char in str */
    s[i] = str[i];       /* assign to s */
s[i] = 0;                /* don't forget to nul-terminate s */

在启用警告的情况下进行编译

始终使用警告启用进行编译,接受代码,直到干净地编译而不发出警告。要启用警告,请将-Wall -Wextra添加到gccclang编译字符串中。 (添加-pedantic以获得其他几个警告)。对于clang,您可以使用-Weverything。对于 VS (windoze上为cl.exe),请添加/W3(或使用/Wall启用所有警告)。

阅读并理解每个警告。他们将识别任何问题,以及它们发生的确切线。您可以通过简单地聆听编译器告诉您的内容,从大多数教程中学到很多关于编码的知识。

如果您还有其他问题,请使用这些建议然后编辑您的问题(或询问新问题)。

修改后的其他评论

Gakuo,显然你仍然在努力整理字符串/字符数组处理以使扩展工作。正如我在评论中提到的那样,每当你遇到这样的问题时,拿起键盘并开始啄食,希望你能够修补足够长的时间,神圣的介入会以某种方式引导你找到解决方案(它不会......)。

相反,首先拿起一张8 1/2 x 11张纸(方格纸效果很好)并写出你的原始字符串,然后计划从原始字符串到你需要的最终字符串所需的每一步(不要忘记在你的布局中代表'\0'

例如,您可以从原始字符串开始:

+---+---+---+
| F | X |\0 |
+---+---+---+

下一步是表示为您的扩展腾出空间的转变(您将原始角色留在原处,因为您只需覆盖它):

+---+---+---+---+---+---+---+
| F | X |   |   |   |   |\0 |
+---+---+---+---+---+---+---+

现在需要将"X+YF+"复制到'X'的位置,导致:

+---+---+---+---+---+---+---+
| F | X | + | Y | F | + |\0 |
+---+---+---+---+---+---+---+

然后只需重复此过程,直到完全展开N次为止。正如您所做的那样,您将能够确定扩展N次的模式 - 也就是说是时候拿起键盘了。

对于您的情况,不要手动循环所有内容,而是使用memmovememcpy来帮助在字符串中进行移位和复制。 (你可以通过循环手动移动和复制 - 只要你能找到更多的字母为你循环变量而不仅仅是'i')。让记忆功能有所帮助,您可以执行以下操作:

注意:已修改,以适应sexpandonce()的更改长度

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

#define NTIMES  2
#define MAXC  100

#define SDEF "FX"       /* string (default) */
#define XEXP "X+YF+"    /* X expansion */
#define YEXP "-FX-Y"    /* Y expansion */

/* returns pointer to 1-past last expansion on success, NULL otherwise */
char *expandonce (char *s)
{
    char *p = s,
        *expanded = NULL;
    size_t lxexp = strlen (XEXP),
        lyexp = strlen (YEXP);

    while (*p) {
        if (*p == 'X') {        /* handle 'X' found */
            size_t lens = strlen (s);               /* get new length of s */
            if (MAXC > lens + lxexp) {                  /* room to expand? */
                size_t lenp = strlen (p);               /* total to shift */
                /* shift chars to right of 'X' by lxexp-1 including '\0' */
                memmove (p + lxexp, p + 1, lenp + lxexp - 1);
                memcpy (p, XEXP, lxexp);                /* copy expansion */
                p += lxexp;                             /* add offset */
                expanded = p;                           /* set return */
            }
        }
        else if (*p == 'Y') {   /* handle 'Y' found */
            size_t lens = strlen (s);                   /* same for 'Y' */
            if (MAXC > lens + lyexp) {
                size_t lenp = strlen (p);
                memmove (p + lyexp, p + 1, lenp + lyexp - 1);
                memcpy (p, YEXP, lyexp);
                p += lyexp;
                expanded = p;
            }
        }
        else    /* handle all other chars */
            p++;
    }

    return expanded;
}

/* returns number of successful expansion loops */
int expandntimes (char *s, int n)
{
    int i = 0;
    char *p = s;

    for (i = 0; i < n; i++)
        if ((p = expandonce (s)) == NULL)
            break;

    return i;
}

int main (int argc, char **argv) {

    char str[MAXC] = "";
    int n = 0;

    if (argc > 1 && strlen (argv[1]) < MAXC - 1)
        strcpy (str, argv[1]);
    else
        strcpy (str, SDEF);

    printf ("string: %s\nX_exp : %s\nY_exp : %s\n\n", str, XEXP, YEXP);

    n = expandntimes (str, NTIMES);

    if (n == 0) {
        fputs ("error: no expansions possible.\n", stderr);
        return 1;
    }

    printf ("%d expansions => %s\n", n, str);

    return 0;
}

(注意:这是一个最小的例子 - 您应该在逐步完成设计时验证是否涵盖了所有角落案例)

示例使用/输出

你的例子:

$ ./bin/expand2 "FX"
string: FX
X_exp : X+YF+
Y_exp : -FX-Y

2 expansions => FX+YF++-FX-YF+

略有不同的字符串:

$ ./bin/expand2 "XY"
string: XY
X_exp : X+YF+
Y_exp : -FX-Y

2 expansions => X+YF++-FX-YF+-FX+YF+--FX-Y

答案 1 :(得分:0)

你得到了内存错误,因为你试图在内存中写入你不应该做的任何事情。如果你想追加字符串,你必须使用strcat()函数!线s [i] =“X + YF +”;永远不会编译,因为你试图写入多个字符,只允许一个字符。我认为最好将s全局化并将字符串逐个附加到带有strcat的s,直到你创建字符串。您可以访问main中的全局变量。然后打印字符串s。