Garbage being printed when using strcpy

2019-01-20 14:25发布

问题:

I have a function that will parse some data coming in. My problem is that after using strncpy I get some garbage when I try to print it. I try using malloc to make the char array the exact size.

Code:

void parse_data(char *unparsed_data)
{
char *temp_str;
char *pos;
char *pos2;
char *key;
char *data;
const char newline = '\n';

int timestamp = 0;

temp_str = (char*)malloc(strlen(unparsed_data));

g_print("\nThe original string is: \n%s\n",unparsed_data);


//Ignore the first two lines
pos = strchr(unparsed_data, newline);
strcpy(temp_str, pos+1);
pos = strchr(temp_str, newline);
strcpy(temp_str, pos+1);

//Split the line in two; The key name and the value
pos = strchr(temp_str, ':'); // ':' divides the name from the value
pos2 = strchr(temp_str, '\n'); //end of the line
key = (char*)malloc((size_t)(pos-temp_str)-1); //allocate enough memory
data = (char*)malloc((size_t)(pos2-pos)-1);

strncpy(key, temp_str, (size_t)(pos-temp_str));
strncpy(data, pos + 2, (size_t)(pos2-pos));

timestamp = atoi(data);

g_print("size of the variable \"key\" = %d or %d\n", (size_t)(pos-temp_str), strlen(key));
g_print("size of the variable \"data\" = %d or %d\n", (size_t)(pos2-pos), strlen(data));

g_print("The key name is %s\n",key);
g_print("The value is %s\n",data);
g_print("End of Parser\n");
  }

Output:

The original string is: 
NEW_DATAa_PACKET
Local Data Set 16-byte Universal Key
Time Stamp (microsec): 1319639501097446
Frame Number: 0
Version: 3
Angle (deg): 10.228428

size of the variable "key" = 21 or 22
size of the variable "data" = 18 or 21
The key name is Time Stamp (microsec)
The value is 1319639501097446
F32
End of Parser

Run it again:

  The original string is: 
  NEW_DATAa_PACKET
  Local Data Set 16-byte Universal Key
  Time Stamp (microsec): 1319639501097446
  Frame Number: 0
  Version: 3
  Angle (deg): 10.228428

  size of the variable "key" = 21 or 25
  size of the variable "data" = 18 or 18
  The key name is Time Stamp (microsec)ipe 
  The value is 1319639501097446
  F
  End of Parser

回答1:

Your strncpy(data, pos + 2, (size_t)(pos2-pos)); doesn't add a terminating \0 character at the end of the string. Therefore when you try to print it later, printf() prints your whole data string and whatever is in the memory right after it, until it reaches zero - that's the garbate you're getting. You need to explicitly append zero at the end of your data. It's also needed for atoi().

Edit: You need to allocate one more byte for your data, and write a terminating character there. data[len_of_data] = '\0'. Only after that it becomes a valid C string and you can use it for atoi() and printf().



回答2:

Your results are because strncpy does not put a null character at the end of the string.



回答3:

You need to malloc() +1 byte for a string, so it can append the zero when you do strcpy(), but the strncpy will not append zero as well you need a extra byte for it.



回答4:

One problem: What if there's no newline?

Undefined behaviour:

pos = strchr(temp_str, newline);
strcpy(temp_str, pos+1);

The source and destination of strcpy must not overlap.



回答5:

You have to remember in allocating space for a string to add one byte for the terminating '\0' character. You have to be careful with strncpy, especially if you are used to using strcpy, strcat, or sprintf. Those three functions terminate the string with '\0'. strncpy copies a number of bytes that you specify, and makes no assumption of terminating the string.

You assume that responsibility by making sure you place a '\0' at the end of the character buffer to which you copied. That means you have to know the starting the position and the length of the copy and put a '\0' one byte past the sum of the starting position and length.

I chose to solve a sample problem slightly differently, but it still involves knowing the length of what I copied.

In this case, I use strncpy to take the first 9 characters from pcszTestStr1 and copy them to szTestBuf. Then, I use strcpy -- which terminates the string with a zero -- to append the new part of the sentence.

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

int n;
int argv_2;

char szTestBuf[100] = {0};
char * pcszTestStr1 = 
"This is a very long, long string to be used in a C example, OK?";

int main(int argc, char *argv[])
{
    int rc = 0;

    printf("The following sentence is too long.\n%s\n", pcszTestStr1);
    strncpy(szTestBuf, pcszTestStr1, 9);
    strcpy(szTestBuf + 9, " much shorter sentence.");
    printf("%s\n", szTestBuf); 

    return rc;
}

Here's the output of running test.c compiled gcc -o test test.c.

cnorton@hiawatha:~/scratch$ ./test
The following sentence is too long.
This is a very long, long string to be used in a C example, OK?
This is a much shorter sentence.
cnorton@hiawatha:~/scratch$