您好,我正在用 C 语言为 Raspberry 开发一个程序(正在进行的项目可以在 here 找到)。
我注意到 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");
}
描述
主函数调用文件task1.c
中定义的task1
函数。每次验证条件 (val_read && (!alarm_on))
时,该函数都会在文件夹 ./pics/
中创建一个文件(在模拟中,每 2 次满足此条件)循环)。该功能只允许文件夹中包含 10 个文件。如果已经有 10 个,它将删除最旧的一个并通过调用函数 takePic
创建新文件。
文件名存储在字符串数组 char* names[24];
中,变量 nexEl
指向该数组中名称为最旧的文件,以便将其替换为刚刚创建的新文件的名称。
问题
问题如下:数组 char* names[24]
在第一次迭代时正确填充,但在第二次迭代中某些元素已被覆盖。当文件夹具有最大文件数 (10) 时,可能会更新阵列,就会出现问题。
似乎对 printf
的调用覆盖了它的一些元素,例如其中一个元素包含字符串 “删除/var/www/html/*.jpg 时出错,可能不存在\n "
打印在函数 takePic
内。
我在管理字符串数组时遗漏了什么或做错了什么?
实用功能
此处简要描述并报告了程序中使用的其他功能。
函数 getDateStr
以 yyyy_mm_dd_hh_mm_ss
格式构建表示当前日期的字符串。
函数filesByName
构建一个字符串数组,其中每个字符串都是文件夹./
中文件的名称,从最后创建的文件到最新的文件排序。
函数printFiles
打印前一个数组。
void getDateStr(char str[20])
{
char year[5], common[3];
time_t t = time(NULL);
struct tm tm = *localtime(&t);
str[0]='\0';
sprintf(year, "%04d", tm.tm_year+1900);
strcat(str, year);
sprintf(common, "_%02d", tm.tm_mon + 1);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_mday);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_hour);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_min);
strcat(str, common);
sprintf(common, "_%02d", tm.tm_sec);
strcat(str, common);
//printf("%s\n", str);
}
unsigned int countFiles(char* dir)
{
unsigned int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(dir); /* There should be error handling after this */
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) { /* If the entry is a regular file */
file_count++;
}
}
return file_count;
}
void printFiles(char* names[24], unsigned int file_count)
{
for (int i=0; i<file_count; i++)
{
printf("%s\n", names[i]);
}
}
unsigned int filesByName(char* names[24], char* dir)
{
unsigned int file_count = 0;
DIR * dirp;
struct dirent * entry;
dirp = opendir(dir); /* There should be error handling after this */
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_type == DT_REG) { /* If the entry is a regular file */
//strncpy(names[file_count], entry->d_name,20);
//names[file_count] = malloc(24*sizeof(char));
names[file_count] = entry->d_name;
file_count++;
}
}
closedir(dirp);
char temp[24];
if (file_count>0)
{
for (int i=0; i<file_count-1; i++)
{
for (int j=i; j<file_count; j++)
{
if (strcmp(names[i], names[j])>0)
{
strncpy(temp, names[i],24);
strncpy(names[i], names[j],24);
strncpy(names[j], temp, 24);
}
}
}
}
return file_count;
}
为了进行模拟,我还创建了以下函数(digitalRead
实际上是 Raspberry 的 wiringPi
C 库的函数):
int digitalRead(int INPIN)
{
static int res = 0;
res = !res;
return res;
}
最佳答案
在task1
中,您有char *names[24]
。这是一个 char
指针数组。
在 filesByName
中,您可以这样做
名称[file_count] = 条目->d_name;
但应该这样做
names[file_count] = strdup(entry->d_name);
因为您无法保证 d_name
在函数返回后甚至在循环内持续存在或唯一。您已经接近注释掉的 malloc
调用。
因为您[可能]多次调用filesByName
,所以它需要检查names[file_count]
是否为非空,以便它可以执行free
在执行 strdup
之前[从先前的调用中释放旧的/过时的值]以防止内存泄漏。
同样,在task1
中,
strcpy(names[nexEl], picname); //ERROR HERE
会有类似的问题,应该替换为:
if (names[nexEl] != NULL)
free(names[nexEl]);
names[nexEl] = strdup(picname);
可能还有其他地方需要类似的调整。并且,请注意,在 task1
中,names
应预先初始化,将为 NULL
解决此问题的另一种方法是更改 names
[各处] 的定义:
char *names[24];
至:
char names[24][256];
这可以避免一些 malloc
/free
操作。
关于对 printf 的调用似乎覆盖了字符串数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49476365/