我遇到了一个c程序的问题:int变量意外更改。
以下是有关问题的全部内容:
我试图读取一个txt文件,它看起来像:

2013/12/31 19:53:54, started, /activeJob/start/ Failed
2013/12/31 19:55:55, ended, retCode = 6, Couldn't resolve host name, /activeJob/finish/ Failed
2014/01/01 08:06:55, started, /activeJob/start/ Failed
2014/03/04 12:16:55, started, /activeJob/start/ Success
2014/03/04 12:17:25, ended, retCode = 0, No error, /activeJob/finish/ success
2014/03/04 13:57:21, started, /activeJob/start/ Success

它是一个记录任务开始/完成时间的日志文件。我想分析日志文件,并在一个订单时间(最新的第一个)内找到完成的任务记录。例如,我将尝试读取最后一行,它显示任务正在运行。因此,我忽略它,继续阅读最后的第二行。一般来说,下两行成对地“结束”和“开始”可以标记为记录。
我的环境是:Centos6.5(通过VMWaire安装)。
下面是源代码,它使用libccgi:
#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>
#include "json/json.h"
#include "ccgi.h"
#include  <errno.h>

const char *queryName = "account";
const char *queryPage = "pageIndex";
const char *startAction = "/activeJob/start/";
const char *finishAction = "/activeJob/finish/";
const char *contentDes[] = {"there is backup processing, start at :","there is no backup"};
const float pageNums = 8.0;



const char * jsonStringCreate(json_object *jsonObj,int statueCode, char *content, int totalPages)
{
    json_object_object_add(jsonObj, "statueCode", json_object_new_int(statueCode));
    json_object_object_add(jsonObj, "content", json_object_new_string(content));
    json_object_object_add(jsonObj, "totalPages", json_object_new_int((int)totalPages));

    //the memory of returned string is under control of jsonObj
    return json_object_get_string(jsonObj);
}

char *mallocString(char *string)
{
    char *returnString = malloc(sizeof(char) * (1 + strlen(string)));
    strcpy(returnString, string);
    //owner free the returned string
    return returnString;
}


/* File must be open with 'b' in the mode parameter to fopen() */
/* Set file position to size of file before reading last line of file */
char* fgetsr(char* buf, int n, FILE* binaryStream)
{
  long fpos;
  int cpos;
  int first = 1;

  if (n &lt; 1 || (fpos = ftell(binaryStream)) == -1 || fpos == 0)
    return NULL;

  cpos = n - 1;
  buf[cpos] = '\0';

  for (;;)
  {
    int c;

    if (fseek(binaryStream, --fpos, SEEK_SET) != 0 ||
        (c = fgetc(binaryStream)) == EOF)
      return NULL;

    if (c == '\n' && first == 0) /* accept at most one '\n' */
      break;
    first = 0;

    if (c != '\r') /* ignore DOS/Windows '\r' */
    {
      unsigned char ch = c;
      if (cpos == 0)
      {
        memmove(buf + 1, buf, n - 2);
        ++cpos;
      }
      memcpy(buf + --cpos, &ch, 1);
    }

    if (fpos == 0)
    {
      fseek(binaryStream, 0, SEEK_SET);
      break;
    }
  }

  memmove(buf, buf + cpos, n - cpos);

  return buf;
}

</code></pre>
<pre><code>
int main(int argc, char const *argv[], char **env)
{
    int statueCode = 0;
    int totalPages = 0;
    char *content = NULL;
    json_object *jsonObj = json_object_new_object();

    printf("Content-type: text/plain; encoding=utf-8\n\n");

    CGI_varlist *vl;
    const char *name;
    CGI_value *value;
    int i;

    if ((vl = CGI_get_all("/tmp/cgi-upload-XXXXXX") ) == 0)
    {
        // CGI error
        // fputs("CGI_get_all() failed\r\n", stdout);
        statueCode = 501;
        content = mallocString("CGI error");

    }
    else
    {
        //get the CGI env parameters, next to get the query parameter
        char *accountName = NULL;
        int queryIndex = -1;
        for (name = CGI_first_name(vl); name != 0; name = CGI_next_name(vl))
        {
            value = CGI_lookup_all(vl, 0);
            for ( i = 0; value[i] != 0; ++i)
            {

                if (strcmp(name, queryName) == 0)
                {
                    accountName = malloc(sizeof(char) * (strlen(value[i]) + 4 + 1));
                    strcpy(accountName, value[i]);
                    strcat(accountName, ".log");
                }
                else if (strcmp(name, queryPage) == 0)
                {
                    queryIndex = atoi(value[i]);
                }
            }
        }

        if (accountName == NULL || queryIndex &lt; 0)
        {
            statueCode = 502;
            content = mallocString("wrong query parameters format");
        }
        else
        {
            //for test, need remove
            FILE *logFile = fopen("./[email protected]", "rb");
            // FILE *logFile = fopen(accountName, "r");
            char *lastLineStr = NULL;
            int lineNum = 0;

            if (logFile != NULL)
            {
                //log file is found

                char *line = NULL;
                size_t len = 0;
                ssize_t read;
                while( (read = getline(&line, &len, logFile)) != -1)
                {
                    // printf("%s\n", line);
                    if (strstr(line, finishAction) != 0)
                    {
                        /* code */
                        totalPages ++;
                    }
                    lineNum ++;
                }
                free(line);

                int realPage = ceil(totalPages/pageNums);
                if (queryIndex > realPage)
                {
                    /* code */
                    statueCode = 503;
                    content = mallocString("wrong parameter: query index is beyond the total page");
                }
                else
                {
                    //log file exist and query index is valid
                    long startIndex = 0, endIndex = 0, currentIndex = 0;;
                    startIndex = (queryIndex - 1) * pageNums;
                    endIndex = (queryIndex) *pageNums;

                    currentIndex = startIndex;

                    char buf[256];
                    int isFinishFound = -1;
                    int  isStartFound = -1;
                    char *finishContetn[] = {};
                    char *startContent[] = {};
// this is the core part
                    while(fgetsr(buf, sizeof(buf), logFile) != NULL && currentIndex lt; endIndex)
                    {
                        if (strstr(buf, finishAction) != 0)
                        {
                            /* code */
                            if (isFinishFound &gt; 0)
                            {
                                /* code */
                                continue;
                            }
                            else
                            {
                                isFinishFound = 1;
                                isStartFound = -1;
                                finishContetn[currentIndex] = mallocString(buf);

                            }

                        }// strange part:
                        else if (strstr(buf, startAction) != 0)
                        {
                            //finish is not found, means: a start with no finish pairs
                            if (isFinishFound &lt; 0)
                            {
                                /* code */
                                continue;
                            }
                            else
                            {

                                if (isStartFound &lt; 0)
                                {
                                    /* code */
                                    startContent[currentIndex] = mallocString(buf);
                                    isStartFound = 1;
                                    isFinishFound = -1;
                                    currentIndex ++;
                                }
                                else
                                {
                                    continue;
                                }
                            }
                        }
                    }


                }


            }
            else
            {
                //log file is not found
                statueCode = 400;
                content = mallocString("not found the account log");

                // printf("not found\n");
                // fprintf(stderr, "%d: %s\n", errno, strerror(errno) );
            }
            if (logFile)
            {
                fclose(logFile);
            }

        }



    }

    return 0;
}

libjson和libccgi被放置在正确的位置,我构建并使其像:

/usr/local/bin/clang -I /usr/include -DHAVE_SSL -DCLDMAN -DCLDMAN_USE_RETRY -DUSE_PROXY -c -MMD -fPIC -g -DHAVE_SSL -DCLDMAN -I../../build/include -I../../build/include/curl -I../../build/include/json -I../../build/include/svmdisk -o getLog.o getLog.c
/usr/local/bin/clang -o getLog getLog.o -L../../build/lib -lm -lccgi  -ljson

在终端没有错误。
我遇到的问题是intisStartFound的值有一个奇怪的值134538336。当我按如下方式调试时会发生这种情况:
在while中,currentIndex=1意味着它开始查找第二条记录
它找到“finish”,然后开始执行:

isFinishFound = 1;
isStartFound = -1;
finishContetn[currentIndex] = mallocString(buf);

之后,它再次运行到while,现在isStartFound更改为134538336
我还尝试将isStartFound添加到watch变量。它还显示在“奇怪的部分”(我在代码中添加了这个部分),isStartFound的值从-1变为134538336
我找不到这个价值的来源。我怀疑我构建和链接的方式是错误的。但我没找到。
有人能告诉我怎么调查吗?
谢谢!
====已编辑:
问题主要定位在以下代码:

char buf[256];
int isFinishFound = -1;
int  isStartFound = -1;
while(fgetsr(buf, sizeof(buf), logFile) != NULL && currentIndex  0)
        {
            continue;
        }
        else
        {
            isFinishFound = 1;
            isStartFound = -1;
            finishContetn[currentIndex] = mallocString(buf);

        }

    }// here strange happens: the isStartFound changes!
    else
    {
        // other part
    }
}

fgetsr用于读取文本的一行;isStartFound&isFinishFound是两个掩码,用于显示是否找到“开始”或“完成”记录。
问题有一个前提条件:找到第一条记录,现在我们试图读取最后的第5行(第2行)。文本文件是:
2013/12/31 19:53:54, started, /activeJob/start/ Failed
2013/12/31 19:55:55, ended, retCode = 6, Couldn't resolve host name, /activeJob/finish/ Failed
2014/01/01 08:06:55, started, /activeJob/start/ Failed
2014/03/04 12:16:55, started, /activeJob/start/ Success
2014/03/04 12:17:25, ended, retCode = 0, No error, /activeJob/finish/ success
2014/03/04 13:57:21, started, /activeJob/start/ Success

现在它开始读取第二行并找到“finish”,因此需要标记var:isStartFound=-1。
当程序运行到第一个“}”时,isStartFound是-1。但是当它运行到第二个“}”(即if (strstr(buf, finishAction) != 0)的“}”)时,值会改变:siStartFound = 134538336!(我在代码中添加了注释)如您所见,这里什么都没有做!
这是我的问题,我觉得奇怪的地方。(抱歉代码太长。如果这个版本仍然困扰着你,请告诉我。)

最佳答案

问题是这个声明:

char *finishContetn[] = {};

这将finishContetn声明为指针的空数组。如果为空,则无论使用什么索引访问此数组,都将超出界限。
分配给此数组时:
finishContetn[currentIndex] = mallocString(buf);

你会写得越界,而且会有undefined behavior。在这种情况下,您将覆盖其他变量所在的堆栈,例如isStartFound变量。
解决这个问题的方法是设置一个固定的大小,或者使用一个动态的“数组”。动态数组解决方案要求您将变量声明为指向指针(指向char)的指针,并使用realloc来(重新)分配数组。
有点像
char **finishContent = NULL;
size_t finishContentSize = 0;  /* Current size of the array */

...

char **temp = realloc(finishContent, sizeof(finishContent[0]) * finishContentSize + 1);
if (temp != NULL)
{
    finishContent = temp;
    finishContent[finishContentSize++] = malloc(...);
}

请注意,我使用一个临时变量返回realloc,这是因为如果realloc失败,那么它将不会为您释放finishContent,如果您直接分配给finishContent,那么您将丢失原始指针,以后也无法将其释放。
还要注意,我使用free。即使当sizeof(finishContent[0])finishContent时,这也会起作用,因为NULL是一个纯编译时运算符,它不会创建任何运行时代码。
当然,您可能需要修改代码以适合您的应用程序,但上面的内容应该足以给您一个想法。

关于c - 整数值更改意外,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22832053/

10-09 08:44