>the filename is guarranteed to be 46 characters long, [otherwise the program would have stopped before now] so the null is being place on the end
An issue being addressed is as follows.
Code:
#include <stdio.h>
#include <string.h>
#define SITA_FILE_LENGTH 46
int main(void)
{
const char pathname[] = "R3AP200307_CIRPTESTER_00001_20030701164512.SND";
char filename [ SITA_FILE_LENGTH ];
strncpy(filename, pathname, SITA_FILE_LENGTH);
filename [ SITA_FILE_LENGTH ] = '\0'; /* access out-of-bounds */
printf("filename = \"%s\"\n", filename);
return 0;
}
If you declare
Code:
char filename[46]; /* index from 0 - 45 */
then trying to use
Code:
filename[46] = '\0';
is one beyond the end of the array, and behavior is undefined. So at best, you would need to do this.
Code:
filename [ SITA_FILE_LENGTH - 1 ] = '\0'; /* null terminate last character */
And if your filename needs to hold 46 significant characters, the buffer size must be 47 to make room for the terminating null.
Now, the strncpy/strncat issue relates to the following.
Code:
#include <stdio.h>
#include <string.h>
void show(const char *s, size_t size)
{
size_t i;
for(i = 0; i < size; ++i)
{
printf("s[%lu] = %d\n", (long unsigned)i, s[i]);
}
}
void foo(char *s, const char *t, size_t size)
{
puts("strncpy");
strncpy(s, t, size - 1);
show(s, size);
}
void bar(char *s, const char *t, size_t size)
{
puts("strncat");
s[0] = '\0';
strncat(s, t, size - 1);
show(s, size);
}
int main(void)
{
char a[] = {1,2,3,4,5}, b[] = "hello world";
foo(a, b, sizeof a);
bar(a, b, sizeof a);
return 0;
}
/* my output
strncpy
s[0] = 104
s[1] = 101
s[2] = 108
s[3] = 108
s[4] = 5
strncat
s[0] = 104
s[1] = 101
s[2] = 108
s[3] = 108
s[4] = 0
*/
Note that the strncpy version did not null terminate the string. You attempt to correct this by adding the null after the call to strncpy, but you may have attempted to change the wrong character.
A final point about using strncpy is that if you have an array of 256 chars and you use strncpy to copy "hello" into the array (passing the maximum size of 256), all of the 256 elements of the array will be modified -- the remaining characters would be set to '\0'. This may be overkill, since a string needs only to end with a '\0'. Using strncat in this situation would only copy the five characters and add a null. (The "add a null" part is why one less than the buffer size should be passed.)
Putting these couple of things together, here is an example with different sizes of strings.
Code:
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 256
#define SITA_FILE_LENGTH 46
char * get_filename(const char * path, char * buffer, size_t limit)
{
const char * start = strrchr(path, '/');
if ( start != NULL )
{
*buffer = '\0'; /* empty the string to concatenate to */
strncat(buffer, start + 1/* after '/' */, limit - 1/* room for null*/);
return buffer;
}
return NULL;
}
int main(void)
{
char filename [ SITA_FILE_LENGTH + 1 ]; /* 46 chars + null */
const char pathname[] [ BUF_SIZE ] =
{
"/root/mydir/R3AP200307_CIRPTESTER_00001_20030701164512.SND",
"/root/mydir/__R3AP200307_CIRPTESTER_00001_20030701164512.SND",
"/root/mydir/R3AP200307_CIRPTESTER_00001_20030701164512.SND__",
"/root/mydir/R3AP200307_CIRPTESTER_00001.SND",
};
size_t i;
for(i = 0; i < sizeof pathname / sizeof *pathname; ++i)
{
printf("pathname = \"%s\"\n", pathname[i]);
if ( get_filename(pathname[i], filename, sizeof filename) != NULL )
{
printf("filename = \"%s\"\n", filename);
}
putchar('\n');
}
return 0;
}
/* my output
pathname = "/root/mydir/R3AP200307_CIRPTESTER_00001_20030701164512.SND"
filename = "R3AP200307_CIRPTESTER_00001_20030701164512.SND"
pathname = "/root/mydir/__R3AP200307_CIRPTESTER_00001_20030701164512.SND"
filename = "__R3AP200307_CIRPTESTER_00001_20030701164512.S"
pathname = "/root/mydir/R3AP200307_CIRPTESTER_00001_20030701164512.SND__"
filename = "R3AP200307_CIRPTESTER_00001_20030701164512.SND"
pathname = "/root/mydir/R3AP200307_CIRPTESTER_00001.SND"
filename = "R3AP200307_CIRPTESTER_00001.SND"
*/