C 对printf的调用似乎覆盖了字符串数组
您好,我正在为C语言中的覆盆子开发一个程序(可以找到正在进行的项目) 我注意到C 对printf的调用似乎覆盖了字符串数组,c,arrays,c-strings,C,Arrays,C Strings,您好,我正在为C语言中的覆盆子开发一个程序(可以找到正在进行的项目) 我注意到task1函数中有一些错误,因此我在我的桌面(运行Ubuntu)中创建了一个等效的程序来查找错误,其中task1被重新调整如下: #include <stdio.h> #include <string.h> #include <stdlib.h> #include "stub.h" #include "globals.h" #include "utils.h" #include &l
task1
函数中有一些错误,因此我在我的桌面(运行Ubuntu)中创建了一个等效的程序来查找错误,其中task1
被重新调整如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stub.h"
#include "globals.h"
#include "utils.h"
#include <pthread.h>
#define INPIN 25
void takePic(char picname[24]);
//This thread reads the PIR sensor output
void task1()
{
unsigned char val_read = 0;
static unsigned char alarm_on = FALSE;
static const unsigned int maxNumPics=10;
static char folderPath[] = "/home/usr/Documents/alarmSys_rasp/alarm_new/pics/";
char fileNameTodelete[73];
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
//INITIALIZING
pinMode(INPIN, INPUT);
//create folder where to save pics
createFolder(folderPath);
char* names[24];
char picname[24];
int res = 0;
picname[0] = '\0';
static unsigned int numPicsInFolder;
//delete if more than 10 files
while((numPicsInFolder = filesByName(names, folderPath))>maxNumPics)
{
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
strcat(fileNameTodelete, names[0]);
printf("%s\n", fileNameTodelete);
remove(fileNameTodelete);
}
static unsigned int nexEl;
nexEl = numPicsInFolder % maxNumPics;
printf("Entering while\n");
while(1)
{
//static const unsigned int del = 300;
val_read = digitalRead(INPIN);
if (val_read && (!alarm_on)) //motion detected
{
printf("\nDetected movement\n");
if (numPicsInFolder >= maxNumPics)
{
printf("\nMax num pics\n");
fileNameTodelete[0] = '\0';
strcat(fileNameTodelete, folderPath);
strcat(fileNameTodelete, names[nexEl]);
printFiles(names, numPicsInFolder);
printf("File to be deleted %d: %s, ", nexEl, names[nexEl]);
//printf("%s\n", fileNameTodelete);
if ((res = remove(fileNameTodelete))!=0)
{
printf("Error deleting file: %d\n", res);
}
}
else
{
printf("\nNot reached max num pics\n");
numPicsInFolder++;
}
//update buffer
takePic(picname);
printf("value returned by takePic: %s\n", picname);
//names[nexEl] = picname;
strcpy(names[nexEl], picname); //ERROR HERE
printFiles(names, numPicsInFolder);
printf("curr element %d: %s\n",nexEl, names[nexEl]);
nexEl++;
nexEl %= maxNumPics;
printf("\nDetected movement: alarm tripped\n\n");
alarm_on = TRUE;
/*Give some time before another pic*/
}
else if (alarm_on && !val_read)
{
alarm_on = FALSE;
printf("\nAlarm backed off\n\n");
}
}
}
void takePic(char picname[24])
{
/*Build string to take picture*/
int err;
//finalcmd is very long
char finalcmd[150];
finalcmd[0] = '\0';
getDateStr(picname);
char cmd1[] = "touch /home/usr/Documents/alarmSys_rasp/alarm_new/pics/";
char cmdlast[] = "";
strcat(finalcmd, cmd1);
strcat(picname, ".jpg");
strcat(finalcmd, picname);
strcat(finalcmd, cmdlast);
system(finalcmd);
if ((err=remove("/var/www/html/*.jpg"))!=0)
{
printf("Error deleting /var/www/html/*.jpg, maybe not existing\n" );
}
//system(finalcmd_ln);
//pthread_mutex_lock(&g_new_pic_m);
g_new_pic_flag = TRUE;
printf("\nPicture taken\n\n");
}
对于模拟,我还创建了以下函数(digitalRead
实际上是树莓的wiringPi
C库的函数):
在
task1
中,您有char*名称[24]
。这是一个char
指针数组
在filesByName
中,您可以
name[文件计数]=条目->文件名代码>
但我们应该做什么
name[文件计数]=strdup(条目->文件名)代码>
因为您不能保证d_name
在函数返回后或甚至在循环中持续存在或唯一。您已经完成了注释掉的malloc
调用
由于您多次调用filesByName
[可能],因此它需要检查名称[文件计数]
是否为非空,以便在执行strdup
之前对其执行free
操作[从以前的调用中释放旧的/过时的值],以防止内存泄漏
同样,在任务1中
strcpy(names[nexEl], picname); //ERROR HERE
将出现类似问题,应替换为:
if (names[nexEl] != NULL)
free(names[nexEl]);
names[nexEl] = strdup(picname);
可能还有其他地方需要进行类似调整。并且,请注意,在task1
中,名称应预先初始化将NULL
解决此问题的另一种方法是将名称的定义从以下位置更改为[everywhere]:
char *names[24];
致:
这避免了一些malloc
/free
操作。getDateStr()
使用总是太小的char
缓冲区。也许还存在其他问题
void getDateStr(char str[20]) {
char year[5], common[3];
....
sprintf(common, "_%02d", tm.tm_mon + 1); // BAD, common[] needs at least 4
更多错误检查的替代方案
char *getDateStr(char *str, size_t sz) {
if (str == NULL || sz < 1) {
return NULL;
}
str[0] = '\0';
time_t t = time(NULL);
struct tm *tm_ptr = localtime(&t);
if (tm_ptr == NULL) {
return NULL;
}
struct tm tm = *tm_ptr;
int cnt = snprintf(year, sz, "%04d_%02d_%02d_%02d_%02d_%02d",
tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
if (cnt < 0 || cnt >= sz) {
return NULL;
}
return str;
}
char*getDateStr(char*str,size\u t sz){
if(str==NULL | | sz<1){
返回NULL;
}
str[0]='\0';
时间t=时间(空);
struct tm*tm_ptr=localtime(&t);
如果(tm_ptr==NULL){
返回NULL;
}
struct tm=*tm_ptr;
int cnt=snprintf(年份,sz,“%04d\uU%02d\uU%02d\uU%02d\uU%02d\uU%02d”,
tm.tm_年+1900,tm.tm_月+1,tm.tm_日,
tm.tm_小时、tm.tm_分钟、tm.tm_秒);
如果(cnt<0 | | cnt>=sz){
返回NULL;
}
返回str;
}
您是指公共缓冲区,还是说函数有20个缓冲区输入,而我用24个缓冲区输入?@FrancescoBoisprintf(公共,“\u02d”,tm.tm\u mon+1)代码>尝试将至少4个字符写入字符公共[3]代码>。示例:'
,'0'
,'3'
,'\0'
对于今天的时间戳,这是缓冲区溢出并导致未定义的行为char common[3]
太小了。这是真的……这是一个改进,但可能不是主要问题我在字符串数组的管理方面遗漏了什么或做错了什么?
您使用的strcat()
太频繁了。看看sprintf()
或者更棒的是:snprintf()
和:您的字符缓冲区似乎太小了
将指针条目->数据名称
复制到名称[文件计数]
。在下一次迭代中,file\u count
1更大,names[file\u count]=entry->d\u name
将同一指针复制到下一个名称[文件计数]
。代码需要将字符串的内容保存在entry->d_name
处。讨论了一些想法。从第一次运行来看,它似乎是免费的(名称[nexEl]);使程序崩溃,而不是魔术数字256,考虑使用最大的文件名长度可能从<代码>条目> dyNeord。例如,sizeof entry->d_name
当它是一个数组时,或者可能。@Craig Estey感谢您的帮助……问题是名称被声明为char*names[24]
,它的元素需要分配适当的空间,例如如果(names[i]=NULL)malloc(names[i],sizeof(char)*24)
或将其声明为char名称[10][24]
并正确更改代码
char names[24][256];
void getDateStr(char str[20]) {
char year[5], common[3];
....
sprintf(common, "_%02d", tm.tm_mon + 1); // BAD, common[] needs at least 4
char *getDateStr(char *str, size_t sz) {
if (str == NULL || sz < 1) {
return NULL;
}
str[0] = '\0';
time_t t = time(NULL);
struct tm *tm_ptr = localtime(&t);
if (tm_ptr == NULL) {
return NULL;
}
struct tm tm = *tm_ptr;
int cnt = snprintf(year, sz, "%04d_%02d_%02d_%02d_%02d_%02d",
tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
if (cnt < 0 || cnt >= sz) {
return NULL;
}
return str;
}