我遇到了一个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 < 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 < 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 > 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 < 0)
{
/* code */
continue;
}
else
{
if (isStartFound < 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
在终端没有错误。
我遇到的问题是int
isStartFound
的值有一个奇怪的值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/