简体   繁体   English

C-连接结构字符串元素

[英]C - Struct string elements are concatenated

i have two string elements in my structure 我的结构中有两个字符串元素

struct mystruct{
    char mydate[10];
    char mytime[5];
};

They will store strings of type "XX:YY" and "XX-YY-ZZZZ" respectively. 它们将分别存储类型为“ XX:YY”和“ XX-YY-ZZZZ”的字符串。

But when I am assigning some value into these variables 但是当我给这些变量赋值时

struct mystruct *mystruct = (struct mystruct*)malloc(sizeof(struct mystruct));
strcpy(mystruct->mydate, "01-01-1970");
strcpy(mystruct->mytime, "00:01");

mydate variables is printing this: mydate变量正在打印此:

01-01-197000:01

I am missing something? 我想念什么吗? Can you help me? 你能帮助我吗? Thanks in andance! 谢谢安迪斯!

  • EDITED with more info 编辑更多信息
  • don't works even if I increase the size by one 即使我将尺寸增加一倍也不起作用

You have undefined behavior since there is not sufficient room in mydate to contain strings of the format "MM-DD-YYYY" - don't forget the implicit null terminator at the end. 您的行为不确定,因为mydate没有足够的空间来容纳格式为“ MM-DD-YYYY”的字符串-不要忘记最后的隐式空终止符。

What you're specifically observing is that the lack of the null terminator means that the output function ( puts , printf , or whatever you're using) continues to read characters after the string ends. 您具体观察到的是,缺少null终止符意味着输出函数( putsprintf或您正在使用的任何东西)在字符串结束后继续读取字符。 It so happens that there isn't any padding between mydate and mytime in your case, so the value in mytime appears to be part of the string as well. 碰巧的是,在您的情况下, mydatemytime之间没有任何填充,因此mytime中的值mytime似乎是字符串的一部分。

Remember, since arrays decay to pointers when passed to functions, there is no way for a function with an array parameter to know when it is done reading the array; 请记住,由于数组在传递给函数时会衰减为指针,因此带有数组参数的函数无法知道何时完成读取数组。 the null terminator acts as a sentinel value for this purpose. 为此,空终止符充当标记值。

Solution: Increase the size of both mydate and mytime to accommodate the null terminator as well. 解决方案:增加mydatemytime的大小,以同时容纳空终止符。

since you complained that your code did not work even with increased sizes, here is an example which works correctly: 由于您抱怨代码即使增大大小也无法正常工作,因此以下示例可以正常工作:

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

struct mystruct1 {
    char mydate[11];
    char mytime[6];
};

void main() {
    struct mystruct1 *mystruct1 = (struct mystruct1*)malloc(sizeof(struct mystruct1));

    strcpy(mystruct1->mydate, "01-01-1970");
    strcpy(mystruct1->mytime, "00:01");

    printf("date: %s, time: %s\n", mystruct1->mydate, mystruct1->mytime);
}

In this example every array has enough space to keep the string with the null terminator. 在此示例中,每个数组都有足够的空间来使字符串带有空终止符。 So, you can compare it to your code. 因此,您可以将其与您的代码进行比较。

In general it is also possible to keep sizes as in your example. 通常,也可以像示例中那样保留大小。 But you need to always remember that the end of the string cannot be determined automatically and will require you to use specific function, like strncpy instead of strcpy . 但是您需要始终记住,字符串的结尾不能自动确定,并且需要您使用特定的功能,例如strncpy而不是strcpy printf will not work directly as well. printf也不能直接工作。 So here is another example: 因此,这是另一个示例:

struct mystruct2 {
    char mydate[10];
    char mytime[5];
};

void main() {
    struct mystruct2 *mystruct2 = (struct mystruct2*)malloc(sizeof(struct mystruct2));

    strncpy(mystruct2->mydate, "02-02-2970", 10);
    strncpy(mystruct2->mytime, "00:02", 5);

    // need top prepare standard strings with terminator for printf
    char mydate[11]; // still need [11] for printf to work
    char mytime[6];

    strncpy(mydate, mystruct2->mydate, 10);
    mydate[10] = 0; // make sure to put a string terminator here
    strncpy(mytime, mystruct2->mytime, 10);
    mytime[5] = 0;

    printf("date: %s, time: %s\n", mydate, mytime);
}

The above makes sense in some situation where you are really tight on the memory, but should not be used in generic cases. 在某些情况下,当您确实需要大量内存时,上面的方法是有意义的,但在一般情况下不应使用。

The are at least two problems with the code. 该代码至少有两个问题。

1) You are writing too much in the mydate and mytime . 1)您在mydatemytime中写的太多了。 The fix is either to allocate more memory in the struct, ie, char mydate[10+1]; 解决方法是在结构中分配更多的内存,即char mydate[10+1]; & char mytime[5+1]; char mytime[5+1]; . Or just don't write the NULL terminator. 或者只是不写NULL终止符。 A solution for that, since you know the size in advance, use memcpy(mystruct->mydate, "01-01-1970", sizeof(mystruct->mydate)); 一种解决方案,因为您事先知道大小,所以请使用memcpy(mystruct->mydate, "01-01-1970", sizeof(mystruct->mydate)); or similar memcpy(mystruct->mytime, "00:01", 5); 或类似的memcpy(mystruct->mytime, "00:01", 5); .

2) The second part, print out, you are not showing (hint). 2)第二部分,打印出来,您没有显示(提示)。 So if you don't store the NULL -terminator then print out needs to be a little more delicate as shown in the example below. 因此,如果不存储NULL终止符,则打印输出需要更加精细,如下面的示例所示。

// Possible dynamic max size
printf("date: %.*stime: %.*sThe\n",
       (int) sizeof(mystruct->mydate), mystruct->mydate,
       (int) sizeof(mystruct->mytime), mystruct->mytime);

// Fixed max size
printf("date: %.10stime: %.5sEnd\n",
       mystruct->mydate,
       mystruct->mytime);

Either way, the print out will be: 无论哪种方式,打印输出都将是:

date: 01-01-1970time: 00:01The
date: 01-01-1970time: 00:01End

The printf -syntax used maximizes the length of the string printed. 使用的printf -syntax使打印的字符串的长度最大。

BTW, your printout, 01-01-197000:01 , is likely the result of the compiler placing the memory layout of struct mystruct directly after each other in memory. 顺便说一句,您的打印输出为01-01-197000:01 ,可能是编译器将struct mystruct的内存布局直接struct mystruct放置在内存中的结果。 The the resulting memory layout is equivalent to 产生的内存布局等效于

struct mystruct {
    char my[15];
}

where the compiler knows that mydate starts at offset 0, and mytime starts at offset 10. This, if you filled your struct in the order of your example you first get "01-01-1970\\0" followed by "01-01-197000:01\\0" (where the last write is out of scope for the struct). 编译器知道mydate从偏移量0开始,而mytime从偏移量10开始。如果按示例顺序填充结构,则首先得到"01-01-1970\\0"然后是"01-01-197000:01\\0" (其中最后一次写入超出了该结构的范围)。 So printing the date with printf("%s", mystruct->mydate); 因此,使用printf("%s", mystruct->mydate);打印日期printf("%s", mystruct->mydate); gives you your sequence output. 给你你的序列输出。

On the other hand, had you decided to write you data in the reverse order, 另一方面,如果您决定以相反的顺序写入数据,

strcpy(mystruct->mytime, "00:01");
strcpy(mystruct->mydate, "01-01-1970");

the output of 输出

printf("date: %s, time: %sEnd\n", mystruct->mydate, mystruct->mytime);

would be 将会

date: 01-01-1970, time: End

since you time was overwritten my the null terminator of the mydate string copy. 由于您的时间被mydate字符串副本的null终止符覆盖。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM