我正在用 C 语言编写一个 grep 程序。为了确定是否应将收到的当前行打印到屏幕上,我使用了一个名为 reportLineMatchRec 的函数。
在此函数中,我使用另一个名为 updateConExpWithStr2 的函数来解析 reportLineMatchRec() 中使用的字符串之一。
不幸的是,我不断收到 valgrind 错误,说在使用 strlen() 和 strncat() 时,该函数内部使用了未初始化的值,即使我初始化了所有值。
更新:我更新了函数updateConExpWithStr1()
和updateConExpWithStr2()
,因此gcc警告消失了,现在我收到了一个valgrind错误(也在下面更新)。我添加到 valgrind check --track-origins=yes 参数,该参数指出初始化问题的根源在于 commandParser 模块内 fillRoundBrackets()
内的 malloc (添加以下)。我还是没能解决这个问题。
代码:
结构:
typedef enum {REGULAR, POINT, ROUND_BRACKETS, BRACKETS} partClassifier;
union expressionPartInfo {
char xy[2];
char *str1OrStr2;
char regularChar;
}expressionPartInfo;
typedef struct partInExpression
{
union expressionPartInfo expressionPartInfo ;
partClassifier partClassifier;
} partInExpression;
typedef struct parsedCommandStruct
{
char *expressionToSearch;
char *origExpressionToSearch;
char *concatenatedExpression;
int lengthOfOrigExpression;
int numOfExpressionParts;
bool a;
int aNum;
bool b;
bool c;
bool i;
bool n;
bool v;
bool x;
bool E;
struct partInExpression *arrayOfExpressionParts;
} parsedCommandStruct;
更新了matchInLine.c相关函数:
void updateConExpWithStr1(parsedCommandStruct *parsedCommand, char **endOfString, int partIndex, char **orPtr,
int *str1size,char **orPtrcopy){
char *copyStr1OrStr2 = malloc(parsedCommand->lengthOfOrigExpression+1);
strcpy(copyStr1OrStr2, parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2);
*endOfString = parsedCommand->concatenatedExpression+strlen(parsedCommand->concatenatedExpression);
*orPtr = strstr(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2, "|");
*orPtrcopy=(*orPtr)+1;
**orPtr = '\0';
*str1size = strlen(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2);
strcat(parsedCommand->concatenatedExpression, parsedCommand->arrayOfExpressionParts[partIndex].
expressionPartInfo.str1OrStr2);
strcpy(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2, copyStr1OrStr2);
free(copyStr1OrStr2);
}
void updateConExpWithStr2(parsedCommandStruct *parsedCommand, int partIndex, char **orPtr,
int const*str1size, char **endOfString, char **orPtrcopy){
int str2size=0;
**endOfString = '\0';
str2size = strlen(*orPtrcopy);
strncat(parsedCommand->concatenatedExpression, *orPtrcopy, str2size);
}
void reportLineMatchRecE(int partIndex, lineInText *currentLineToCheck, parsedCommandStruct *parsedCommand,
int *linesAfterMatchCounterPtr, int *prevLinesCounter, int *matchFlag){
int j=0; char *orPtr = NULL; int str1size = 0; char *endOfString = NULL; char *orPtrcopy = NULL;
while(partIndex < parsedCommand->numOfExpressionParts){
if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == REGULAR) {
updateConExpWithRegChr(parsedCommand, &partIndex);
}
else if (parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == POINT){
for (j = ASCII_LOWEST_CHAR; j < ASCII_HIGHEST_CHAR+1; j++) {
updateConExpWithChr(j, parsedCommand, &endOfString);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
*endOfString='\0';
}
return;
}
else if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == BRACKETS){
for (j = parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.xy[0];
j < parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.xy[1]+1; j++) {
updateConExpWithChr(j, parsedCommand, &endOfString);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
*endOfString='\0';
}
return;
}
else if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == ROUND_BRACKETS){
updateConExpWithStr1(parsedCommand, &endOfString, partIndex, &orPtr ,&str1size, &orPtrcopy);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
updateConExpWithStr2(parsedCommand, partIndex, &orPtr, &str1size, &endOfString, &orPtrcopy);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
return;
}
}
if(partIndex == parsedCommand->numOfExpressionParts){
strcpy(parsedCommand->expressionToSearch, parsedCommand->concatenatedExpression);
reportLineMatch(currentLineToCheck, *parsedCommand, linesAfterMatchCounterPtr, prevLinesCounter, matchFlag);
return;
}
}
commandParser.c相关函数:
int fillRoundBrackets(parsedCommandStruct *parsedCommand, int indexOfParts, char *str1OrStr2){
parsedCommand->arrayOfExpressionParts[indexOfParts].partClassifier = ROUND_BRACKETS;
char *placeOfClosingBracket = strstr(str1OrStr2, ")");
int str12Size = placeOfClosingBracket-str1OrStr2 - 1;
parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = NULL;
parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = malloc(200);//str12Size+1);
strncpy(parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2, str1OrStr2+1, str12Size);
return str12Size+1;
}
void buildArrayOfExpressionParts(parsedCommandStruct *parsedCommand){
int numOfParts = computeNumOfParts(parsedCommand->expressionToSearch); int i=0, indexOfParts=0;
parsedCommand->arrayOfExpressionParts = NULL;
parsedCommand->arrayOfExpressionParts = malloc(numOfParts * sizeof(partInExpression));
for(i=0; i<(int)strlen(parsedCommand->expressionToSearch); i++)
{
if(parsedCommand->expressionToSearch[i] == '.')
{
parsedCommand->arrayOfExpressionParts[indexOfParts].partClassifier = POINT;
}
else if(parsedCommand->expressionToSearch[i] == '[')
{
fillBrackets(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i+1],
parsedCommand->expressionToSearch[i+3]);
i=i+4;
}
else if(parsedCommand->expressionToSearch[i] == '(') {
parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = NULL;
i = i + fillRoundBrackets(parsedCommand, indexOfParts, parsedCommand->expressionToSearch + i);
}
else if(parsedCommand->expressionToSearch[i] == '\\')
{
fillRegularChar(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i+1]);
i=i+1;
}
else {
fillRegularChar(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i]);
}
indexOfParts++;
}
}
void createAndFillCommand(int argc, char *argv[], parsedCommandStruct **parsedCommand) {
int indexOfExpressionArg = INITIALIZED_VALUE;
indexOfExpressionArg = searchExpressionArgumentIndex(argc, argv);
*parsedCommand = (parsedCommandStruct *) malloc(sizeof(struct parsedCommandStruct));
initializeCommandArgs(parsedCommand);
(*parsedCommand)->expressionToSearch = (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
strcpy((*parsedCommand)->expressionToSearch, argv[indexOfExpressionArg]);
(*parsedCommand)->origExpressionToSearch = (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
strcpy((*parsedCommand)->origExpressionToSearch, argv[indexOfExpressionArg]);
(*parsedCommand)->lengthOfOrigExpression = strlen((*parsedCommand)->expressionToSearch); // delete?
(*parsedCommand)->numOfExpressionParts = computeNumOfParts((*parsedCommand)->expressionToSearch);
updateArgumentsOfCommandStruct(argc, argv, *parsedCommand);
if((*parsedCommand)->E){
buildArrayOfExpressionParts(*parsedCommand);
(*parsedCommand)->concatenatedExpression = (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
strcpy((*parsedCommand)->concatenatedExpression, "");
}
}
main.c:
void receiveAndExecute(parsedCommandStruct *parsedCommand, FILE **stream)
{
ssize_t lineSize = INITIALIZED_VALUE; int matchFlag = 0;
lineInText *currentLine = NULL;
int lineIndex = FIRST_LINE_INDEX, counterForC = INITIALIZED_VALUE,
linesAfterMatchCounter = INITIALIZED_VALUE, sumOfBytes = INITIALIZED_VALUE, prevLinesCounter = INITIALIZED_VALUE;
currentLine = malloc(sizeof *currentLine);
initializeCurrentLine(currentLine);
while (1)
{
readLine(stream, &lineSize, currentLine);
FillLineStruct(currentLine, lineIndex, sumOfBytes);
sumOfBytes = (int)lineSize + sumOfBytes;
lineIndex++;
initializeConcatinateExp(parsedCommand);
if(lineSize<0)
break;
reportLineMatchRec(0, currentLine, parsedCommand, &linesAfterMatchCounter, &prevLinesCounter, &matchFlag);
printLineToOutput(currentLine, parsedCommand, &counterForC, false, &linesAfterMatchCounter,
&prevLinesCounter, &matchFlag);
}
printLineToOutput(currentLine, parsedCommand, &counterForC, true, NULL, NULL, NULL);
freeLine(¤tLine);
}
int main(int argc, char* argv[])
{
parsedCommandStruct *parsedCommand = NULL;
FILE *filePtr = NULL;
bool useFile = false;
useFile = isUsingFile(argc, argv);
createAndFillCommand(argc, argv, &parsedCommand);
if (useFile)
{
filePtr = openFile(argv[argc-1]);
receiveAndExecute(parsedCommand, &filePtr);
fclose(filePtr);
}
else
{
receiveAndExecute(parsedCommand, &stdin);
}
freeParsedCommandStruct(parsedCommand);
free(parsedCommand);
return 0;
}
更新了 valgrind 报告
==7832== Conditional jump or move depends on uninitialised value(s)
==7832== at 0x4C2E1EB: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7832== by 0x401BF7: updateConExpWithStr1 (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x401F48: reportLineMatchRecE (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x4020A4: reportLineMatchRec (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x402280: receiveAndExecute (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x402377: main (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== Uninitialised value was created by a heap allocation
==7832== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7832== by 0x40108C: fillRoundBrackets (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x401218: buildArrayOfExpressionParts (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x40142D: createAndFillCommand (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x40233B: main (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==
最佳答案
将其从评论移至答案。
这段代码非常密集,很难粘贴到注释中,因此我添加了一些空格,并且我看到您已经删除了不必要的项目,例如转换malloc()的返回
.
这都是关于编译器警告的内容,包括您没有收到的警告。
一般来说,编译器警告不是您修复的东西,而是您理解的东西。一旦您了解了它告诉您的内容,修复通常是免费且显而易见的。
warning: assignment makes pointer from integer without a cast
编译器告诉您,在下面标记的行中,一侧是整数,一侧是指针 - 是不是很清楚这里发生了什么:
void updateConExpWithStr1(parsedCommandStruct parsedCommand, char **endOfString,
int partIndex, char **orPtr, int *str1size) {
*endOfString = parsedCommand.concatenatedExpression
+ strlen(parsedCommand.concatenatedExpression);
*orPtr = strstr(
parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
"|");
// THIS NEXT LINE IS WRONG
str1size = *orPtr - parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2;
strncat(parsedCommand.concatenatedExpression,
parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
(size_t)str1size); // THIS LINE TOO
}
str1size
不是一个大小,它是一个指向大小的指针,所以这是有各种问题的。
所编写的代码在指针应在的位置存储了一个整数值,这意味着调用者看不到传回的大小。这可能是一个错误。
然后,后面标记为错误的行恰好可以正确运行,即使有两种错误。 strncat()
期望将大小作为第三个参数,但它给出了一个转换为整数的指针,这对于大小来说永远不是正确的事情,除了这次,因为整数未正确存储为指针。怎么样!
但是仅仅添加一个*
只能解决技术问题,最好首先通过良好的命名约定来避免这种情况。如果你的函数是:
void updateConExpWithStr1(parsedCommandStruct parsedCommand, char **endOfString,
int partIndex, char **orPtr, int *pStr1size) {
...
*pStr1size = blah // integral result
strncat(parsedCommand.concatenatedExpression,
parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
*pStr1size);
}
这里我们不仅正确存储结果,而且通过更改名称来提醒您它是一个指针,让您更容易通过查看来判断这不仅仅是一个整数大小。
<小时/>我希望这里的教训是,您应该认真对待编译器警告,以理解它们为目标,而不仅仅是让它们消失。
当您将 (size_t) str1size
放入对 strncat()
的调用中时,我非常确信您这样做是为了消除编译器警告您没有这样做的警告。不明白,那很危险。
通过添加强制转换,您告诉编译器“相信我”,因此这是一个隐藏在众目睽睽之下的错误(直到我写完这篇文章才注意到它)。
这是所有优秀 C 程序员都养成的一门纪律:渴望编译器警告,并理解每一个警告。始终将它们打开到最大,并且始终将它们包含在任何 SO 帖子中。
关于c - valgrind : Conditional jump or move depends on uninitialised value using strlen() strncat(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59432052/