Question

I have been using strcat to join several strings. Everything appears to be correct, prints:

/proc/573/fd/ <- with the backslash
13            <- length

After I try to copy the "src" string with strcpy to another string, the trailing character doesn't print in either the "dest" or the "src" strings:

/proc/573/fd <- same string prints without the backslash?
13           <- length is unchanged?

If I call strlen the length shows it is unchanged though?

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

// This function counts the number of digit places in 'pid'
int pid_digit_places(int pid)
{
    int n = pid;
    int places = 0;
    while (n)
        n /= 10;
        places++;
    return places;
}

char *construct_path(int pid, char *dir)
{
    // get count of places in pid
    int places = pid_digit_places(pid); 
    char *pid_str = calloc(places, sizeof(char)); 

    // create string of pid 
    sprintf(pid_str, "%d", pid); 

    char *proc = "/proc/";
    size_t plen = strlen(proc);
    size_t dlen = strlen(dir) + 1;
    char *path = calloc(plen + dlen + places, sizeof(char));

    strcat(path, proc);
    strcat(path, pid_str);
    strcat(path, dir);

    return path;
}

void fd_walk(int pid)
{
    char *fd = "/fd/";
    char *fdpath = construct_path(pid, fd);

    // prints "/proc/573/fd/ - as expected    
    printf("Before: %s\n", fdpath); 

    // shows a length of 13
    printf("Size Before: %d\n", (int)strlen(fdpath));  


    char *test = calloc(strlen(fdpath) + 1, sizeof(char));
    strcpy(test, fdpath);

    // prints "/proc/573/fd" no trailing "/"
    printf("Copied Str: %s\n", test); 

    //shows a length of 13 though
    printf("Copied Size: %d\n", (int)strlen(test)); 

    // prints "/proc/573/fd" no trailing "/" now    
    printf("After: %s\n", fdpath); 

    // still shows length of 13
    printf("Size After: %d\n", (int)strlen(fdpath));         
}

int main(void)
{
    // integer to create path around
    int pid = 573; 
    fd_walk(pid);
    return 0;
}

I'm compiling on gcc-4.8.2 with -Wall:

gcc -o src src.c -Wall 

I've popped this small example into ideone.

I've made sure to add an extra space for the null-terminator when allocating memory.

I've thought to re-examine how I'm intializing my pointers first and haven't seen anything wrong? How is the string printing as expected with printf and then after copying it, printf prints something different -- undefined behavior?

Was it helpful?

Solution

I have executed your exact code with no troubles. Nonetheless, I see two possible problems:

// This function counts the number of digit places in 'pid'
int pid_digit_places(int pid)
{
    int n = pid;
    int places = 0;
    while (n) { // <-- The braces were missing here.
        n /= 10;
        places++;
    }
    return places;
}

char *construct_path(int pid, char *dir)
{
    // get count of places in pid
    int places = pid_digit_places(pid);

    // You need "places" bytes for the digits, plus one for the zero
    char *pid_str = calloc(places + 1, sizeof(char));

However, in general, I wouldn't waste time to allocate exactly the memory I needed; the extra code more than compensates in size and complexity.

Just make a guess on the largest possible value, and enforce that guess:

// avoid pid_digit_places altogether
pid_str = malloc(16);
if (pid > 999999999999L) {
    // fprintf an error and abort.

    // Better yet, see whether this is a limit #define'd in the OS,
    // and place an appropriate compile-time # warning. Chances are
    // that unless your code's trivial, running it on a system with
    // such large PIDs (and therefore likely so different an arch!)
    // would cause some other troube to pop up.
    // With an # error in place, you save also the pid check!
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top