C 对printf的调用似乎覆盖了字符串数组

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

您好,我正在为C语言中的覆盆子开发一个程序(可以找到正在进行的项目)

我注意到
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个缓冲区输入?@FrancescoBoi
sprintf(公共,“\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;
}