views:

146

answers:

4

Hi, While working with pointers in C, I have been experiencing a very incosistent result, I am working with a token which is a byte string which i need to make a directory path. a token consists of the date as a prefix in the format of 20101129(2010-oct-29) and then a 20byte string follows, thus a token would look like 20101102A2D8B328CX9RDTBDE373, the method is supposed to return a path that looks like 2010/11/02/A2D8/B328/CX9R/DTBD/E373.

Now with the method that i used in the code provided below, returns strings which have unwanted characters while the code looks OK, the code is provided below

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

#define token "20101102A2D8B328CX9RDTBDE373"
#define SLASH "/"

int main()
{
    char *mainstring = (char*)malloc(strlen(token));
    char *nextstring = (char*)malloc(strlen(token));
    char tokenarr[50] = token;
    char patharr[50];
    char pathmem[50];
    char *fullstring = (char*)malloc(strlen(token));

    char yrstr[4]="";
    char yrmem[4]="";
    char yrarr[4]="";

    char monstr[2]="";
    char monmem[2]="";
    char monarr[2]="";

    char daystr[2]="";
    char daymem[2]="";
    char dayarr[2]="";

    memcpy(mainstring,token,strlen(token));


    memcpy(yrarr,tokenarr,4);
    strncpy(yrstr,mainstring,4);
    memcpy(yrmem,mainstring,4);

    puts(yrarr);
    puts(yrstr);
    puts(yrmem);


    mainstring = mainstring +4;
    memcpy(monarr,tokenarr+4,2);
    strncpy(monstr,mainstring,2); 
    memcpy(monmem,mainstring,2);

    puts(monarr);    
    puts(monstr); 
    puts(monmem);    

    mainstring = mainstring+2;
    memcpy(dayarr,tokenarr+6,2);
    strncpy(daystr,mainstring,2);
    memcpy(daymem, mainstring,2);

    puts(dayarr);
    puts(daystr);
    puts(daymem);

    strcat(patharr,yrarr); strcat(pathmem,yrmem);
    strcat(patharr,"/"); strcat(pathmem,SLASH);
    strcat(patharr,monarr);strcat(pathmem,monmem);
    strcat(patharr,"/"); strcat(pathmem,SLASH);
    strcat(patharr,dayarr); strcat(pathmem,daymem);

    puts(patharr);
    puts(pathmem);

    mainstring = mainstring +2;
    int i;

    for(i=0;i<5;i++)
    {
        memcpy(nextstring,mainstring,4);
        mainstring = mainstring +4;
        printf("The %d th string is:",i+1);        
        puts(nextstring); strcat(fullstring,"/");
        strcat(fullstring, nextstring);

        puts(fullstring);
    }
    strcat(patharr,fullstring); 
    strcat(pathmem,fullstring);
    puts(patharr);
    puts(pathmem);


return 0;

}

The results from the code are:

2010
2010
2010
11
11m��
11
02m
02
02
2010/11/02m
��m�� 2010 /11/02
The 1 th string is:A2D8
/A2D8
The 2 th string is:B328
/A2D8/B328
The 3 th string is:CX9R
/A2D8/B328/CX9R
The 4 th string is:DTBD
/A2D8/B328/CX9R/DTBD
The 5 th string is:E373
/A2D8/B328/CX9R/DTBD/E373
2010/11/02m /A2D8/B328/CX9R/DTBD/E373
��m�� 2010 /11/02/A2D8/B328/CX9R/DTBD/E373

My main question is, why is it that the characters are included in the resulting strings? what i'm i doing wrong with the pointers?

+7  A: 

strlen returns the length of the string, not including the NULL terminator; therefore memcpy is not copying that, so the resulting string is not terminated. The same applies with your mallocs.

You either need to use strlen() + 1, or use strcpy().

Oli Charlesworth
Thank you, let me add these changes right now
BensonMN
Using strcpy() without allocating strlen()+1 invokes undefined behaviour - writing beyond the end of the allocated space.
Jonathan Leffler
+1  A: 

Strings in C are terminated by a null character ('\0'). Various strings you are using (such as yrstr) are not large enough to contain this null character, and you're not putting a null character into them.

For example, when you do this

strncpy(yrstr,mainstring,4);

no null character gets added to the string because strncpy omit the null character if there is not enough space in the destination string. You need to add the null character yourself, for example like this:

yrstr[4]='\0';

This requires yrstr to be large enough to contain at least five characters.

Martin B
thank you for your response, will let you know of the updated changes
BensonMN
Note too that the arrays like `yrstr[4]` need to be `yrstr[5]` to allow for the trailing NULL.
Jonathan Leffler
+1  A: 

If your goal is to convert "20101102A2D8B328CX9RDTBDE373" into "2010/11/02/A2D8/B328/CX9R/DTBD/E373" then one way would be as follows;

// source string YYYYMMDD<20-char token>
char *src = "20101102A2D8B328CX9RDTBDE373";

// destination string, alloc space for source + 7 slashes + 1 null terminator
char *dest = (char *)calloc(1, strlen(src) + 7 + 1);

// now copy elements of src to dest, inserting intermediate slashes
<your code here>
jarmod