I am new to malloc. So I wanted to test this small code.
I'm getting the "segmentation fault error".
**EDIT: The problem was from not allocation char* name (Thanks to #Zack)
You can see what caused the problem:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct info { char *name; } fileinfo;
void mal (fileinfo **ptr)
{
if ((*ptr = (fileinfo*) malloc(3*sizeof(fileinfo))) == NULL) {
fprintf(stderr,"Memory allocating error #1\n");
exit(1);
}
//that what was causing the error - START
for (j = 0; j < 3; j += 1)
{
(*ptr)[j].name = (char*) malloc(10*sizeof(char*));
}
//that what was causing the error - END
strcpy(ptr[0]->name,"1. A\n"); //line 13
strcpy(ptr[1]->name,"2. B\n");
strcpy(ptr[2]->name,"3. C\n");
}
int main (int argc, char *argv[])
{
fileinfo *files;
int i;
mal(&files); //line 22
for (i = 0; i < 3; i += 1)
{
printf("name=%s\n",files[i].name);
}
free(files);
return 0;
}
Using valgrind:
==5751== Use of uninitialised value of size 8
==5751== at 0x4006EB: mal (mal1.c:13)
==5751== by 0x400747: main (mal1.c:22)
==5751==
==5751== Invalid write of size 4
==5751== at 0x4006EB: mal (mal1.c:13)
==5751== by 0x400747: main (mal1.c:22)
==5751== Address 0x0 is not stack'd, malloc'd or (recently) free'd
What am I doing wrong??!
Thanks in advance.
Your problem is that you need to allocate ptr[i]->name before copying to it. A pointer by itself points to some random area of memory. To use it, you must get good memory that is safe and that is what malloc and calloc, and (new in C++) all do. The example you gave is still a mess, and my correction isn't that great, but you get the idea that every pointer in C and C++ must be allocated from somewhere. And, on the flipside, once you are done with the pointer, you have to free them.
void mal (fileinfo **ptr, int count)
{
if ((*ptr = (fileinfo*) malloc(count*sizeof(fileinfo))) == NULL) {
fprintf(stderr,"Memory allocating error #1\n");
exit(1);
}
for (int i = 0; i < 3; i++) {
char buff[2];
buff[0] = 'A' + i;
buff[1] = 0;
ptr[i]->name = malloc( 10 );
strcpy(ptr[0]->name,"1. %s\n", buff);
}
}
Try with
void mal (fileinfo **ptr) {
if ((*ptr = malloc(3*sizeof(fileinfo))) == NULL) {
perror("Memory allocating error #1\n");
exit(EXIT_FAILURE);
}
if (!(ptr[0]->name = strdup("1. A\n")))
{ perror("string 1"); exit(EXIT_FAILURE);};
if (!(ptr[1]->name = strdup("2. B\n")))
{ perror("string 2"); exit(EXIT_FAILURE);};
if (!(ptr[2]->name = strdup("3. C\n")))
{ perror("string 3"); exit(EXIT_FAILURE);} ;
}
BTW, it would be better to make it a function returning a pointer, like
fileinfo* make() {
fileinfo* ptr = malloc(3*sizeof(fileinfo)));
if (!ptr) { perror("make fileinfo"); exit(EXIT_FAILURE); };
if (!(ptr[0]->name = strdup("1. A\n")))
{ perror("string 1"); exit(EXIT_FAILURE);};
if (!(ptr[1]->name = strdup("2. B\n")))
{ perror("string 2"); exit(EXIT_FAILURE);};
if (!(ptr[2]->name = strdup("3. C\n")))
{ perror("string 3"); exit(EXIT_FAILURE);} ;
return ptr;
}
Then, you need a destructor function like
void destroy(fileinfo*ptr) {
free (ptr[0]->name);
free (ptr[1]->name);
free (ptr[2]->name);
free (ptr);
}
to be called instead of your free at the end of your main
Notice that your code is very ad hoc: the number (i.e. 3) of names is completely built-in. This is wrong design. At the very least, that constant should have been named:
#define NB_FILES 3
Actually, a much better approach would be to declare your structure with a flexible array member:
typedef struct fileinfo_st {
unsigned nbfiles;
char* filenames[];
} Fileinfo;
See this for more. You could even have a variadic function to make such structures.
FIleinfo *make(int, ...);
Which you would call like
Fileinfo* ptr = make (3, "abc","def","ghijklmnop");
or you could decide that that last variadic argument is NULL
BTW, read about undefined behavior. You might be unlucky to have your program not crashing but still be very wrong. And compile with gcc -Wall -g and learn more how to use the gdb debugger and valgrind
Related
So, I have an array of a structures called vitorias (in English, "victories"), an array of structures and an array of that structure and an array of strings.
Structure and arrays:
char **sistema_eq;
typedef struct
{
int id;
char nome[MAX_CHARS];
int vit;
} vitorias;
The problem is that when I use cppcheck it gives an error saying:
(error) Common realloc mistake: 'conj_vit' nulled but not freed upon failure
(error) Common realloc mistake: 'sistema_eq' nulled but not freed upon failure
(error) Common realloc mistake: 'conj_jogos' nulled but not freed upon failure
And, if I use Valgrind, it says that I did 10 allocs and 2 free, but I don't understand what's wrong, because I freed everything in the end I think.
Program:
#include<stdlib.h>
#include<stdio.h>
#include <string.h>
#define MAX_CHARS 1024 /* max characters of a word */
#define MAX_SIZE 5
static int size_until = 0; /*conts the size of sistema_eq and conj_vit*/
static int line = 1; /* counts the number of lines of the stdin */
int ident = 0; /*conts the id of jogos*/
static int size_until = 0; /*counts the size of sistema_eq*/
static int size_until2 = 0;/*counts the size of conj_jogos*/
void a(char nome_jg[],char team1[],char team2[],int score1,int score2);
void A(char nome[]);
char **sistema_eq;
jogo *conj_jogos;
vitorias *conj_vit;
int main()
{
char c;
char nome_jg[MAX_CHARS], team1[MAX_CHARS], team2[MAX_CHARS];
int score1;
int score2;
int i;
conj_jogos = (jogo*)calloc(MAX_SIZE,sizeof(jogo));
memset(conj_jogos,0, MAX_SIZE*sizeof(jogo));
conj_vit = (vitorias*)calloc(MAX_SIZE,sizeof(vitorias));
memset(conj_vit,0, MAX_SIZE*sizeof(vitorias));
sistema_eq = (char**)calloc(MAX_SIZE,sizeof(*sistema_eq));
memset(sistema_eq,0, MAX_SIZE*sizeof(*sistema_eq));
for(i=0;i<MAX_SIZE;i++)
{
sistema_eq[i] = (char*)calloc(1024,sizeof(char));
memset(sistema_eq[i],0, sizeof(char)*1024);
}
while ((c = getchar())!= 'x') {
switch (c)
{
case 'A':
{
scanf("%1023[^:\n]",nome_jg);
remove_esp(nome_jg);
A(nome_jg);
break;
}
case 'a':
{
scanf("%1023[^:\n]:%1023[^:\n]:%1023[^:\n]:%d:%d",nome_jg,team1,team2,&score1,&score2);
remove_esp(nome_jg);
a(nome_jg,team1,team2,score1,score2);
line++;
break;
}
}
}
free(conj_vit);
free(conj_jogos);
free(sistema_eq);
return 0;
}
/*This functions adds a victory and a equipa (team in english) into the corresponding arrays and updates the vitories of each team*/
//Example in El Classico Barcelona vs Real Madrid 1:0, which means Barcelona won
void A(char nome[])
{
if (nome_in_sis(nome) == 1)
{
printf("%d Equipa existente.\n",line);
line++;
}
else
{
if (size_until < MAX_SIZE)
{
strcpy(sistema_eq[size_until],nome);
strcpy(conj_vit[size_until].nome,nome);
conj_vit[size_until].id = size_until;
size_until++;
line++;
}
else
{
conj_vit = realloc(conj_vit,sizeof(vitorias)*(size_until+1));
sistema_eq = realloc(sistema_eq,sizeof(char*)*(size_until+1));
sistema_eq[size_until] = calloc(1024,sizeof(char*));
strcpy(sistema_eq[size_until],nome);
strcpy(conj_vit[size_until].nome,nome);
conj_vit[size_until].id = size_until;
size_until++;
line++;
}
}
}
/*This functions adds a jogo (game in english) and a equipa (team in english) into the array conj_jogos (the array of jogos)*/
void a(char nome_jg[],char team1[],char team2[],int score1,int score2)
{
int vit;
if (jogo_in(nome_jg) == 1)
{
printf("%d Jogo existente.\n",line);
line++;
}
else if ((nome_in_sis(team1) == 0) || (nome_in_sis(team2) == 0))
{
printf("%d Equipa inexistente.\n",line);
line++;
}
else
{
if (size_until2 < MAX_SIZE)
{
conj_jogos[size_until2] = cria_jogo(nome_jg,team1,team2,score1,score2);
if (score1 > score2)
{
vit = procura_vit(team1);
conj_vit[vit].vit++;
}
else
{
vit = procura_vit(team2);
conj_vit[vit].vit++;
}
size_until2++;
}
else
{
size_until2++;
conj_jogos = realloc(conj_jogos,sizeof(jogo)*(size_until2+1));
conj_jogos[size_until2] = cria_jogo(nome_jg,team1,team2,score1,score2);
if (score1 > score2)
{
vit = procura_vit(team1);
conj_vit[vit].vit++;
}
else
{
vit = procura_vit(team2);
conj_vit[vit].vit++;
}
size_until2++;
}
}
}
Sorry if the code looks messy and thanks for the help.
As pointed out in the comments, you never free the data you allocated with calloc in the for loop. Add this loop (or something very similar) near the end of your main:
//...
for(i=0;i<MAX_SIZE;i++) free(sistema_eq[i]); // MUST be before the next line!
free(sistema_eq);
//...
Also, as you use calloc, you don't need any of the memset calls! From the linked documentation for void* calloc( size_t num, size_t size ):
Allocates memory for an array of num objects of size and initializes
all bytes in the allocated storage to zero.
For the 'errors' reported concerning realloc: in cases where a call to realloc fails, the code you use will prevent subsequent freeing of the original data (the address of which was in the pointer), as its address will be replaced with NULL on such a failure! To prevent this, use a temporary pointer, like this:
jogo* temp_jogo = realloc(conj_jogos,sizeof(jogo)*(size_until2+1));
if (temp_jogo != NULL) conj_jogos = temp_jogo;
else {
// In case of failure, we now still have the original conj_jogos
// pointer, which we can then pass to "free" at some point, presumably
// after we've signalled and/or handled the allocation error.
}
Finally (I think), you may like to read this: Do I cast the result of malloc? - which is equally valid for calls to calloc and realloc.
I am writing a grep program in C. In order to determine if the current line received should be printed to the screen, i use a function called reportLineMatchRec.
in this function i use another function named updateConExpWithStr2 to parse one of the strings used in reportLineMatchRec().
unfortunately, i keep getting valgrind errors saying there is uninitialized value being used inside this function, when using strlen() and strncat(), eventhough i initialized all values.
update: i updated the functions updateConExpWithStr1() and updateConExpWithStr2() so the gcc warning is gone and now i'm getting a single valgrind error (also updated below). i added to the valgrind check --track-origins=yes parameter which points out that the source for initialization problem is in the malloc inside fillRoundBrackets() inside commandParser module (added below). I still can't solve the problem.
the code:
the structs:
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;
upadted matchInLine.c relevant functions:
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 relevant functions:
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;
}
updated valgrind report
==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==
Moving this from the comments to an Answer.
This code is exceptionally dense and is really hard to paste into a comment, so I've added some whitespace, and I see you've already removed unnecessary items such as casting the return of malloc().
This is all about compiler warnings, including one you are not getting.
In general, compiler warnings are not things you fix, they are things you understand. Once you understand what it's telling you, the fix is usually free and obvious.
warning: assignment makes pointer from integer without a cast
The compiler is telling you that in the marked line below, one side is an integer and one side is a pointer - isn't it pretty clear what's going on here:
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 is not a size, it's a pointer to a size, so this is all kinds of problematic.
The code as written stores an integer value where a pointer should be, and that means the caller is not seeing the size passed back. That's probably a bug.
Then the later line marked as a bug happens to function correctly even though it's two kinds of wrong. strncat() is expecting a size as the third parameter, but it's given a pointer cast to an integer, which is never the right thing for a size, except this time because the integer was improperly stored as a pointer. How about that!
But just adding a * only solves the technical problem, it's better to avoid this in the first place with good naming conventions. What if your function had been:
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);
}
Here we not only store the result properly, but by changing the name to remind you that it's a pointer, it makes it easier for you tell just by looking that this is not just an integral size.
The lesson here, I hope, is that you should take compiler warnings seriously with a goal of understanding them, not just making them go away.
When you put (size_t) str1size in the call to strncat(), I'm pretty confident you were doing this to silence a compiler warning that you didn't understand, and that's dangerous.
By adding the cast, you told the compiler "trust me", so this was a bug that went into hiding in plain sight (I didn't notice it until I was mostly done writing this post).
This is a discipline that all good C programmers develop: to crave compiler warnings, and to understand every one of them. Always turn them on to the max, and always include them in any SO post.
I need your help in this. I have an average knowledge of C and here is the problem. I am about to use some benchmarks to test some computer architecture stuff (branch misses, cache misses) on a new processor. The thing about it is that benchmarks are in C but I must not include any library calls. For example, I cannot use malloc because I am getting the error
"undefined reference to malloc"
even if I have included the library. So I have to write my own malloc. I do not want it to be super efficient - just do the basics. As I am thinking it I must have an address in memory and everytime a malloc happens, I return a pointer to that address and increment the counter by that size. Malloc happens twice in my program so I do not even need large memory.
Can you help me on that? I have designed a Verilog and do not have so much experience in C.
I have seen previous answers but all seem too complicated for me. Besides, I do not have access to K-R book.
Cheers!
EDIT: maybe this can help you more:
I am not using gcc but the sde-gcc compiler. Does it make any difference? Maybe that's why I am getting an undefined reference to malloc?
EDIT2:
I am testing a MIPS architecture:
I have included:
#include <stdlib.h>
and the errors are:
undefined reference to malloc
relocation truncated to fit: R_MIPS_26 against malloc
and the compiler command id:
test.o: test.c cap.h
sde-gcc -c -o test.s test.c -EB -march=mips64 -mabi=64 -G -O -ggdb -O2 -S
sde-as -o test.o test.s EB -march=mips64 -mabi=64 -G -O -ggdb
as_objects:=test.o init.o
EDIT 3:
ok, I used implementation above and it runs without any problems. The problem is that when doing embedded programming, you just have to define everything you are using so I defined my own malloc. sde-gcc didn't recognize the malloc function.
This is a very simple approach, which may get you past your 2 mallocs:
static unsigned char our_memory[1024 * 1024]; //reserve 1 MB for malloc
static size_t next_index = 0;
void *malloc(size_t sz)
{
void *mem;
if(sizeof our_memory - next_index < sz)
return NULL;
mem = &our_memory[next_index];
next_index += sz;
return mem;
}
void free(void *mem)
{
//we cheat, and don't free anything.
}
If required, you might need to align the memory piece you hand back, so e.g. you always
give back memory addresses that's on an address that's a multiple of 4, 8, 16 or whatever you require.
Trying a thread safe nos answer given above, I am referring his code with some changes as below:
static unsigned char our_memory[1024 * 1024]; //reserve 1 MB for malloc
static size_t next_index = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *malloc(size_t sz)
{
void *mem;
pthread_mutex_lock(&lock);
if(sizeof our_memory - next_index < sz){
pthread_mutex_unlock(&lock);
return NULL;
}
mem = &our_memory[next_index];
next_index += sz;
pthread_mutex_unlock(&lock);
return mem;
}
void free(void *mem)
{
//we cheat, and don't free anything.
}
You need to link against libc.a or the equivilent for your system. If you don't use the standard C lib you won't get any of the startup code that runs before the main function either. Your program will never run....
You could either allocate a block of static data and use that in the place of malloc, like:
// char* fred = malloc(10000);
// equals
static char [100000] fred;
or call the standard malloc for a large block of continuous memory on startup and write yr own malloc type function to divide that down. In the 2nd case you would start benchmarking after the calling the system's malloc as to not effect the benchmarks.
I am sharing the complete approach for Malloc and free it works on every scenario. This is complimented using array. We can also implement using link list for metadata.
There are three Scenarios We have to Cover
Continuous Memory allocation: Allocate memory in continuous manner
Allocated memory between two allocated memory: When Memory is free to allocate in between two allocated memory block. we have to use that memory chunk for allocation.
Allocated from Initial block When Initial block is free.
for detailed You can see in diagram. Diagram for allocating algo of memory
Source code for malloc
#define TRUE 1
#define FALSE 0
#define MAX_ALOCATION_ALLOWED 20
static unsigned char our_memory[1024 * 1024];
static int g_allocted_number = 0;
static int g_heap_base_address = 0;
typedef struct malloc_info
{
int address;
int size;
}malloc_info_t;
malloc_info_t metadata_info[MAX_ALOCATION_ALLOWED] ={0};
void* my_malloc(int size)
{
int j =0;
int index = 0 ;
int initial_gap =0;
int gap =0;
int flag = FALSE;
int initial_flag = FALSE;
void *address = NULL;
int heap_index = 0;
malloc_info_t temp_info = {0};
if(g_allocted_number >= MAX_ALOCATION_ALLOWED)
{
return NULL;
}
for(index = 0; index < g_allocted_number; index++)
{
if(metadata_info[index+1].address != 0 )
{
initial_gap = metadata_info[0].address - g_heap_base_address; /*Checked Initial Block (Case 3)*/
if(initial_gap >= size)
{
initial_flag = TRUE;
break;
}
else
{
gap = metadata_info[index+1].address - (metadata_info[index].address + metadata_info[index].size); /*Check Gap Between two allocated memory (Case 2)*/
if(gap >= size)
{
flag = TRUE;
break;
}
}
}
}
if(flag == TRUE) /*Get Index for allocating memory for case 2*/
{
heap_index = ((metadata_info[index].address + metadata_info[index].size) - g_heap_base_address);
for(j = MAX_ALOCATION_ALLOWED -1; j > index+1; j--)
{
memcpy(&metadata_info[j], &metadata_info[j-1], sizeof(malloc_info_t));
}
}
else if (initial_flag == TRUE) /*Get Index for allocating memory for case 3*/
{
heap_index = 0;
for(j = MAX_ALOCATION_ALLOWED -1; j > index+1; j--)
{
memcpy(&metadata_info[j], &metadata_info[j-1], sizeof(malloc_info_t));
}
}
else /*Get Index for allocating memory for case 1*/
{
if(g_allocted_number != 0)
{
heap_index = ((metadata_info[index -1].address + metadata_info[index-1].size) - g_heap_base_address);
}
else /* 0 th Location of Metadata for First time allocation*/
heap_index = 0;
}
address = &our_memory[heap_index];
metadata_info[index].address = g_heap_base_address + heap_index;
metadata_info[index].size = size;
g_allocted_number += 1;
return address;
}
Now Code for Free
void my_free(int address)
{
int i =0;
int copy_meta_data = FALSE;
for(i = 0; i < g_allocted_number; i++)
{
if(address == metadata_info[i].address)
{
// memset(&our_memory[metadata_info[i].address], 0, metadata_info[i].size);
g_allocted_number -= 1;
copy_meta_data = TRUE;
printf("g_allocted_number in free = %d %d\n", g_allocted_number, address);
break;
}
}
if(copy_meta_data == TRUE)
{
if(i == MAX_ALOCATION_ALLOWED -1)
{
metadata_info[i].address = 0;
metadata_info[i].size = 0;
}
else
memcpy(&metadata_info[i], &metadata_info[i+1], sizeof(malloc_info_t));
}
}
For testing Now Test code is
int main()
{
int *ptr =NULL;
int *ptr1 =NULL;
int *ptr2 =NULL;
int *ptr3 =NULL;
int *ptr4 =NULL;
int *ptr5 =NULL;
int *ptr6 =NULL;
g_heap_base_address = &our_memory[0];
ptr = my_malloc(20);
ptr1 = my_malloc(20);
ptr2 = my_malloc(20);
my_free(ptr);
ptr3 = my_malloc(10);
ptr4 = my_malloc(20);
ptr5 = my_malloc(20);
ptr6 = my_malloc(10);
printf("Addresses are: %d, %d, %d, %d, %d, %d, %d\n", ptr, ptr1, ptr2, ptr3, ptr4, ptr5, ptr6);
return 0;
}
The following code is not working correctly. I'm getting a segfault when I run the program. I ran my program through gdb and found out that the error is occuring in the fillArrays(int**,int) function.
GDB is displaying the following parameters for fillArrays(int**,int):
fillArrays (arrays=0x0,numArrays=3)
Here is the source code to my program
#include <stdlib.h> /* malloc and free */
#define MULTIPLIER 1
#define SMALL 10
#define BIG 20
void allocateSmallArrays(int **arrays,int numArrays) {
int index,freeIndex;
int outerIndex,innerIndex;
arrays = malloc(numArrays*sizeof(int*));
if(arrays == NULL) {
printf("out of memory\n");
exit(1);
}
for(index = 0;index < numArrays;index++) {
arrays[index] = malloc(SMALL*sizeof(int));
if(arrays[index] == NULL) {
printf("out of memory\n");
exit(1);
}
}
}
void fillArrays(int **arrays,int numArrays) {
int outerIndex,innerIndex;
for(outerIndex = 0;outerIndex < numArrays;outerIndex++) {
for(innerIndex = 0;innerIndex < SMALL;innerIndex++)
arrays[outerIndex][innerIndex] = 0;
}
}
void deallocateSmallArrays(int **arrays,int numArrays) {
int index;
for(index = 0;index < numArrays;index++)
free(arrays[index]);
free(arrays);
}
int main(void) {
int numArrays = (3 * MULTIPLIER);
int **arrays = 0;
allocateSmallArrays(arrays,numArrays);
fillArrays(arrays,numArrays);
deallocateSmallArrays(arrays,numArrays);
arrays = 0;
return 0;
}
I was under the assumption that since arrays was allocated in allocateSmallArrays, that passing it through fillArrays would 0 out the allocated arrays and then deallocate in the last function. How do I go about accomplishing this?
The problem is that allocateSmallArrays changes its own copy of the arrays pointer. So the result of the malloc is lost and after the function is done, in the caller arrays is still 0. You could:
Pass a triple pointer int ***arrays and do to *arrays everything you're doing to arrays
Return the pointer instead of void
A C FAQ deals with this very subject.
I am mallocing an array of c strings. After releasing it, I get the following error:
Assembler(87536) malloc: *** error for object 0x108500840: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Why is that? I am pretty sure I am doing the malloc correctly. I'm pretty experienced with memory management, but I am not sure why this is giving me an error. The array is should hold three strings, each of which is 2 characters long.
Here is how I am mallocing the array:
char **reg_store;
reg_store = malloc(3 * (sizeof(char*)));
if (reg_store == NULL) {
fprintf(Out, "Out of memory\n");
exit(1);
}
for (int i = 0; i < 3; i++) {
reg_store[i] = malloc(2 * sizeof(char));
if (reg_store[i] == NULL) {
fprintf(Out, "Out of memory\n");
exit(1);
}
}
Here is how I am freeing it:
for (int i = 0; i < 3; i++) {
free(reg_store[i]);
}
free(reg_store);
Here is what I have in between:
// Keeps a reference to which register has been parsed for storage
int count = 0;
char *reg = NULL;
char *inst_ptr // POINTS TO SOME STRING. EXAMPLE: $t2, $t1, $a0
while (1) {
// Parses the string in inst_ptr with dollar, comma and space as a delimiter.
reg = parse_token(inst_ptr, " $,\n", &inst_ptr, NULL);
if (reg == NULL || *reg == '#') {
break;
}
reg_store[count] = reg;
count++;
free(reg);
}
I am printing out reg after I call parse_token and it does print out correctly. I am also printing out reg_store[count] and it does also print out correctly.
Your problem is here:
reg_store[count] = reg;
free(reg);
and later
free(reg_store[i]);
reg is already freed and you free it another time (not talking about the problems with using it later). to fix this replace
reg_store[count] = reg;
with
strcpy(reg_store[count], reg);
or as suggested in the comments, since you know its two charaters, its better to memcpy it:
memcpy(reg_store[count], reg, 2);
I would suggest adding some printfs (or use the debugger) to see the values of all the malloced pointers just after they have been malloced. Then do the same just before they are freed, to make sure they are the same. Perhaps there is some other rogue code elsewhere in the program that is stomping over memory.
Your problem is in the "in between" code, in particular, right here:
reg_store[count] = reg;
count++;
free(reg);
You allocated reg_store[count] with malloc during your set up, then you overwrite the allocated value with reg and then free reg. The result is a memory leak from the original pointers that were in reg_store and a double-free on each element of reg_store when you try to clean everything up.
You need to copy reg into the memory already allocated in reg_store[count] (watching the size of course) or don't allocate any space for the elements of reg_store before the "in between" code at all.
The error was already pointed out so no need to write it again.
I can however point out that i don't like the way you are handling errors.
void freeRegStore(char** reg_store)
{
int i;
if (reg_store != NULL)
{
for (i = 0; i < 3; i++)
free(reg_store[i]);
free(reg_store);
}
}
char** allocRegStore()
{
int i;
char **reg_store;
reg_store = calloc(3 * (sizeof(char*)), 1);
if (reg_store != NULL)
{
for (i = 0; i < 3; i++)
{
reg_store[i] = malloc(2 * sizeof(char));
if (reg_store[i] == NULL)
{
freeRegStore(reg_store);
return NULL;
}
}
}
return reg_store;
}
In this method, the function allocRegStore will return NULL if there was not enough memory without leaving pieces around.
Then you can handle this case in main and not in the allocation function itself.
I disagree with the use of printf and exit inside functions.
int main()
{
char** reg_store = allocRegStore();
if (reg_store == NULL)
{
puts("Out of memory");
return 1;
}
... do your stuff
freeRegStore();
return 0;
}
I can also say that the memory used by this program will never go out of memory :) i would not worry about that.