【问题标题】:C - Unusual Result When Intertwining Two Char ArraysC - 交织两个字符数组时的异常结果
【发布时间】:2017-02-12 20:29:50
【问题描述】:

我正在开展一个项目,该项目需要将两个字符串“交织”在一起,以便它们交替使用每个字符。 示例:“Apple”和“BEAR”将变为“ABpEpAlRe”

这是我目前的功能:

void printMessage(char name[], char num[])
{
    char eticket[(sizeof(name)/sizeof(char))+((sizeof(num))/sizeof(char))] = ""; //make array with enough space for both strings
    int i;
    for(i=0;i<(sizeof(eticket)/sizeof(char));i++)
    {
        char tmp[1] ={name[i]}; // i have to change the char name[i] and num[i] to its own char array so i can use it in strcat
        char tmp2[1] ={num[i]};
        if(i<(sizeof(name)/sizeof(char))-1) //if name string is finished, don't concatenate
        {
            strcpy(eticket,strcat(eticket, tmp));
        }
        if(i<(sizeof(num)/sizeof(char))-1) //if num string is finished, don't concatenate
        {
            strcpy(eticket,strcat(eticket, tmp2));
        }
    }

    printf("Your name is %s and your flight number is %s.\nYour e-ticket is: %s.\n\n", name, num, eticket);
}

其中 eticket 是最后一个字符串。

结果:

Your name is Connor and your flight number is MIA1050.
Your e-ticket is: CMMoIInAAn11o00r550.

*** stack smashing detected ***: ./a.out terminated
Aborted

我知道堆栈粉碎意味着缓冲区溢出,但更让我担心的是,由于某种我无法弄清楚的原因,num[] 数组在最终字符串中的字符加倍。 而不是“CMMoII ...”应该是“CMoI ...” 这可能是缓冲区溢出的副作用吗?

提前致谢。

【问题讨论】:

  • sizeof(name)sizeof(num) 是指针的大小,而不是调用函数中数组的大小。你可以删除所有sizeof(char),因为它的定义是1。
  • 您需要使用strlen() 而不是sizeof()。对于初学者;可能还有其他问题。
  • 等等等等调试器等等等等

标签: c arrays string buffer concatenation


【解决方案1】:

函数定义:

void printMessage(char name[], char num[]) { ... }

相同
void printMessage(char* name, char* num) { ... }

在函数中,sizeof(name) 等于指针的大小。它不会计算字符串的长度。

您需要使用strlen 而不是sizeof。当您使用strlen 时,您需要为终止空字符添加一个额外的字符。

// eticket is now a VLA.
// Can't use ... = "";
char eticket[strlen(name)+strlen(num)+1];

您还需要更改使用sizeof 的其他代码行。

【讨论】:

  • 使用strlen 使eticket 成为无法初始化的VLA。
【解决方案2】:

其他人指出数组是“通过引用传递”的。所以你不应该使用sizeof(name),因为那只是sizeof(char*)(如果我错了请纠正我;总是8),而是strlen(name)

char tmp[1] ={name[i]}; 
char tmp2[1] ={num[i]};

这可能会得到你想要的,但是为一个元素创建一个 char 数组是非常多余的。相反,只需创建一个字符并使用 & 将指针传递给该字符:

char tmp = name[i];
printf("tmp: %s\n", &tmp);

循环可以减少到只有两行:

void printMessage(char* name, char* num){
   int len = strlen(name) + strlen(num);
   char* eticket = calloc(0,len +1); 
   int i,j,k;

   for(i=0, j=0, k=0; i<len;i++){
      if(j < strlen(name)) strncpy(&eticket[i++],&name[j++],1);
      if(k < strlen(num) ) strncpy(&eticket[i],&num[k++],1);
   }
   printf("Your name is %s and your flight number is %s.\nYour e-ticket is: %s.\n\n", name, num, eticket);
   free(eticket);
}

这可以按照您的意愿进行,并且更清洁。我跳过了整个 strcat(..) 函数,因为它是多余的。我改用strncpy(char * dst, const char * src, size_t len)。 这个怎么运作: - i 保持在 ecket 中的位置。 - j 保留 name 中的位置。 - k 保持在 num 中的位置。

&eticket[i++]

这指向 ecket 数组中的第 i'th 位置(i 之后递增)。这意味着复制到这里的任何内容都将从这里开始。

&name[j++]

这是一个指向 name 数组中的 j'th 元素的指针。这意味着strncpy 将从此处开始读取,并将 1 元素复制到 eticket 数组中。

希望这会有所帮助。

【讨论】:

  • 感谢有关如何清理代码的额外说明。 & 运算符仍然让我陷入循环(呵呵)。
【解决方案3】:

对于经验丰富的 C 程序员来说,C 语言的一个怪癖是数组是“通过引用传递”的,但它却让新的 C 程序员无计可施。一般而言,大多数表达式中使用的数组名称会衰减到其第一个元素的地址。函数将这种情况带到了一个极端情况,其中函数参数中的数组语法实际上是指针类型本身的别名。

因此,您的函数中的namenum 实际上是指针而不是数组,因此sizeof(name) 实际上与sizeof(char *) 相同。

【讨论】:

    【解决方案4】:

    在 C 中,当您使用如下语法传递数组时:

    void printMessage(char name[], char num[])
    

    数组的size信息丢失;您传递的基本上是指向数组开头的指针

    这意味着像sizeof(name)/sizeof(char)这样的表达式在这种情况下等价于:

    sizeof(char *)/sizeof(char)
    

    这是:

    (指针大小)/(字符大小)

    在 32 位架构上,这通常计算为 4(即 4 字节/1 字节)。

    因此,您可能希望在运行时获取输入字符串长度,调用strlen(),并使用malloc() 动态分配输出字符串数组。

    例如

    char * eticket = NULL;
    ...
    
    /* 
     * Dynamically allocate memory for output string buffer.
     * Note: add +1 to consider the string's NUL-terminator.
     */
    eticket = (char *)malloc(strlen(name) + strlen(num) + 1);
    
    /* Check allocation failure */
    if (eticket == NULL)
    {
        /* Error */
        ...
    }
    
    /* Use eticket */
    ...
    
    /* Don't forget to free memory! */
    free(eticket);
    
    /* Avoid dangling pointers */
    eticket = NULL;
    

    【讨论】:

      猜你喜欢
      • 2011-07-17
      • 2012-07-03
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 2018-01-02
      • 1970-01-01
      • 1970-01-01
      • 2016-04-24
      相关资源
      最近更新 更多