奇怪的 Char* 截断
Strange Char* Truncation
我刚回到 C 编程,我遇到了结构中动态 char* 字段的奇怪问题。它开始时完全没问题,长度也合适,但它被截断为 25 个字符,最后一个字符甚至不在原始数组中。
我定义了两个结构和几个全局变量:
struct files_list {
struct files_list* next;
char* fpath;
};
struct job_list {
int len;
off_t size;
struct files_list* files;
struct job_list* next;
};
struct job_list* job_head = NULL;
struct job_list* active = NULL;
(想法是将有一个 "jobs" 的单个链表,多个线程将处理该链表,每个线程都包含该作业的单个文件链表。)
Main 只是调用 ntfw
遍历目录树:
int main(int argc, char** argv) {
// ...
nftw("/tmp/", populate, 100, 0);
// ...
}
对于每个文件和目录,ntfw 调用我的 populate
函数:
int populate(const char *fpath, const struct stat *sb,
int tflag, struct FTW *ftwbuf) {
if (tflag == FTW_F) {
/* #1 CREATE NEW FILE ENTRY */
printf("\n\n");
printf("FPATH: %s\n", fpath);
struct files_list* current_files = malloc(sizeof(struct files_list));
current_files->fpath = malloc(sizeof(fpath) + 1);
strcpy(current_files->fpath, fpath);
current_files->next = NULL;
printf("files_list %s (%i)\n", current_files->fpath, strlen(current_files->fpath));
printf("¤t_files: %p\n", current_files);
/* #2 CREATE NEW ACTIVE JOB */
if (active == NULL) {
struct job_list* job = malloc(sizeof(struct job_list));
job->len = 0;
job->size = 0;
job->files = NULL;
job->next = NULL;
active = job;
}
active->len++;
active->size += sb->st_size;
/* #3 INSERT FILE ENTRY AT THE END OF ACTIVE JOB */
if (active->files == NULL) {
active->files = current_files;
printf("&active->files: %p\n", active->files);
printf("current_files->fpath: %s (%i)\n", current_files->fpath, strlen(current_files->fpath)); // TRUNCATED STRING
printf("active->files->fpath: %s (%i)\n", active->files->fpath, strlen(active->files->fpath));
} else {
struct files_list* x = active->files->next;
while (1) {
if (x == NULL) {
x = current_files;
printf("Added files_list: %s\n", x->fpath);
break;
} else {
printf("next x->next\n");
x = x->next;
}
}
}
/* #4 TIME FOR A NEW JOB */
if (active->size > MAX_BYTES) {
if (job_head == NULL) {
job_head = active;
job_tail = active;
} else {
job_tail->next = active;
}
struct job_list* new_active = NULL;
active = new_active;
job_len++;
}
}
return 0;
}
产生这样的输出:
FPATH: /tmp/.com.google.Chrome.T8MuMk/SingletonSocket
files_list /tmp/.com.google.Chrome.T8MuMk/SingletonSocket (46)
¤t_files: 0x125d1e0
&active->files: 0x125d1e0
current_files->fpath: /tmp/.com.google.Chrome.1 (25)
active->files->fpath: /tmp/.com.google.Chrome.1 (25)
从前两行我们可以看出,文件路径很长,包含 46 个字符,并且已成功 strcpy()
ed 到我的 files_list
结构中。然后在步骤 #2 和步骤 #3 的前几行之间发生了一些事情,将文件名截断为 24 个字符并添加了一个“1”。指针地址表明它仍然是同一个结构对象,而且我没有看到任何可能会弄乱它的操作。
我用过GCC 4.9.2和Clang 3.5.0,他们都有这个问题,所以一定是我哪里做错了。
知道这里发生了什么吗?
这就是问题所在
malloc(sizeof(fpath) + 1);
sizeof(fpath)
将给出指针的大小,因为 fpath
是一个 char *
即 char
指针,你需要 strlen()
malloc(strlen(fpath) + 1);
不要忘记包含 string.h
。
您需要阅读有关 sizeof
运算符的内容,这是来自 1570 草案,§ 6.5.3.4 段落 ¶ 2.
The sizeof operator yields the size (in bytes) of its operand, which may be an
expression or the parenthesized name of a type. The size is determined from the type of
the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
注意:您必须检查 malloc()
函数族中的 return 值,它们 return NULL
失败时发生了,你必须检查几乎每个有一个函数的 return 值,因为这是确保函数正常工作并且没有意外发生的唯一方法,否则为什么会有 return 值为了它?
我刚回到 C 编程,我遇到了结构中动态 char* 字段的奇怪问题。它开始时完全没问题,长度也合适,但它被截断为 25 个字符,最后一个字符甚至不在原始数组中。
我定义了两个结构和几个全局变量:
struct files_list {
struct files_list* next;
char* fpath;
};
struct job_list {
int len;
off_t size;
struct files_list* files;
struct job_list* next;
};
struct job_list* job_head = NULL;
struct job_list* active = NULL;
(想法是将有一个 "jobs" 的单个链表,多个线程将处理该链表,每个线程都包含该作业的单个文件链表。)
Main 只是调用 ntfw
遍历目录树:
int main(int argc, char** argv) {
// ...
nftw("/tmp/", populate, 100, 0);
// ...
}
对于每个文件和目录,ntfw 调用我的 populate
函数:
int populate(const char *fpath, const struct stat *sb,
int tflag, struct FTW *ftwbuf) {
if (tflag == FTW_F) {
/* #1 CREATE NEW FILE ENTRY */
printf("\n\n");
printf("FPATH: %s\n", fpath);
struct files_list* current_files = malloc(sizeof(struct files_list));
current_files->fpath = malloc(sizeof(fpath) + 1);
strcpy(current_files->fpath, fpath);
current_files->next = NULL;
printf("files_list %s (%i)\n", current_files->fpath, strlen(current_files->fpath));
printf("¤t_files: %p\n", current_files);
/* #2 CREATE NEW ACTIVE JOB */
if (active == NULL) {
struct job_list* job = malloc(sizeof(struct job_list));
job->len = 0;
job->size = 0;
job->files = NULL;
job->next = NULL;
active = job;
}
active->len++;
active->size += sb->st_size;
/* #3 INSERT FILE ENTRY AT THE END OF ACTIVE JOB */
if (active->files == NULL) {
active->files = current_files;
printf("&active->files: %p\n", active->files);
printf("current_files->fpath: %s (%i)\n", current_files->fpath, strlen(current_files->fpath)); // TRUNCATED STRING
printf("active->files->fpath: %s (%i)\n", active->files->fpath, strlen(active->files->fpath));
} else {
struct files_list* x = active->files->next;
while (1) {
if (x == NULL) {
x = current_files;
printf("Added files_list: %s\n", x->fpath);
break;
} else {
printf("next x->next\n");
x = x->next;
}
}
}
/* #4 TIME FOR A NEW JOB */
if (active->size > MAX_BYTES) {
if (job_head == NULL) {
job_head = active;
job_tail = active;
} else {
job_tail->next = active;
}
struct job_list* new_active = NULL;
active = new_active;
job_len++;
}
}
return 0;
}
产生这样的输出:
FPATH: /tmp/.com.google.Chrome.T8MuMk/SingletonSocket
files_list /tmp/.com.google.Chrome.T8MuMk/SingletonSocket (46)
¤t_files: 0x125d1e0
&active->files: 0x125d1e0
current_files->fpath: /tmp/.com.google.Chrome.1 (25)
active->files->fpath: /tmp/.com.google.Chrome.1 (25)
从前两行我们可以看出,文件路径很长,包含 46 个字符,并且已成功 strcpy()
ed 到我的 files_list
结构中。然后在步骤 #2 和步骤 #3 的前几行之间发生了一些事情,将文件名截断为 24 个字符并添加了一个“1”。指针地址表明它仍然是同一个结构对象,而且我没有看到任何可能会弄乱它的操作。
我用过GCC 4.9.2和Clang 3.5.0,他们都有这个问题,所以一定是我哪里做错了。
知道这里发生了什么吗?
这就是问题所在
malloc(sizeof(fpath) + 1);
sizeof(fpath)
将给出指针的大小,因为 fpath
是一个 char *
即 char
指针,你需要 strlen()
malloc(strlen(fpath) + 1);
不要忘记包含 string.h
。
您需要阅读有关 sizeof
运算符的内容,这是来自 1570 草案,§ 6.5.3.4 段落 ¶ 2.
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
注意:您必须检查 malloc()
函数族中的 return 值,它们 return NULL
失败时发生了,你必须检查几乎每个有一个函数的 return 值,因为这是确保函数正常工作并且没有意外发生的唯一方法,否则为什么会有 return 值为了它?