C - 交织两个Char数组时的异常结果

时间:2016-10-04 15:27:57

标签: c arrays string buffer concatenation

我正在开发一个项目,需要将两个字符串“交织在一起”,以便它们交替每个字符。 示例:“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 ......” 这可能是缓冲区溢出的副作用吗?

提前致谢。

4 个答案:

答案 0 :(得分:2)

功能定义:

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的其他代码行。

答案 1 :(得分:0)

经验丰富的C语言程序员熟知的C语言的怪癖,但是新的C编码器匆匆到来,就是阵列是通过引用传递的#34;。一般来说,大多数表达式中使用的数组名称将衰减到其第一个元素的地址。函数将其带到极端情况,其中函数参数中的数组语法实际上是指针类型本身的别名。

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

答案 2 :(得分:0)

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

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

有关阵列 size 的信息丢失;你传递的内容基本上是指针到数组的开头。

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

sizeof(char *)/sizeof(char)

是:

  

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

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

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

e.g。

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;

答案 3 :(得分:0)

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

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

这可能会得到你想要的东西,但为一个元素创建一个char数组非常多余。而只是创建一个char并使用&amp;

传递指向该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 保持 eticket 中的位置。   - j 保留名称中的位置。   - k 将位置保留在 num

&eticket[i++]

这指向 eticket 数组中的 i'th 位置(i后来递增)。这意味着复制到此的内容将从此处开始。

&name[j++]

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

希望这有帮助。

相关问题