Im trying to open file with fopen,and to read\write for "huffman tree".
After i've finished reading from the text, I tried to write in another file a "dictionary" that say what is the code for every letter.
I've got an eror that i havnt find something similar except that the reason is old version of eclipse, but it wasn't the problam.
Im programing in c with eclipse in ubuntu.
the main is look like:
int main(){
FILE *fsrc;
node *root;
if( (fsrc = fopen( "src.txt", "r" )) == NULL ){ //
printf( "The file 'src.txt' was not opened\n" );
return 0;
}
else {
printf( "The file 'src.txt' was opened\n" );
}
root = getBinTree(fsrc);
printTree(&(*root));
huffman(root);
return 0;
}
this is the function that writing to to target text
void printhtree(node *n,FILE *trg){
char *str = calloc(1, sizeof(char));
node *ptr=n;
while (!(ptr->m_hls && ptr->m_hrs)){
while(ptr->m_hls){
n=ptr;
ptr = ptr->m_hls;
str = realloc(1,sizeof(char)*(strlength(str)+1));
*(str+strlength(str)-1)='0';
}//while
if(!(ptr->m_hrs)){
printf("%s-%c ",str,ptr->m_ch);
n->m_hls = NULL;
return;
}//if
while(ptr->m_hrs){
n=ptr;
ptr = ptr->m_hrs;
str = realloc(1,sizeof(char)*(strlength(str)+1));
*(str+strlength(str)-1)='1';
}//while
}//while
if (!(ptr->m_ch)){
fputc(ptr->m_ch,trg);
fputc(' ',trg);
fputs(str,trg);
n->m_hls = NULL;
return;
}//if
}//printhtree
and this is the function that activate |pringhtree" function:
void drawTree(node *n,FILE *trg){
while(!(n))
printhtree(n,trg);
}
the error is on the first line of draw tree :
"void drawTree(node *n,FILE *trg)"
and it says:
"multiple markers at this line
bad character sequence encountered
stray '\252' in program, and the same line with the numbers 254,342,200.
there is the same error also where i wrote the names of all the function in the beginning of the program.
thank you very much
This is an important issue in your code
str = realloc(1,sizeof(char)*(strlength(str)+1));
For many reasons
The syntax is wrong, as it is you are realloc()ing the address 0x01.
You should not immediately overwrite the pointer, because if an error occurs then you will be unable to recover, a good usage of realloc() would be like
void *tmp = realloc(str, 1 + strlength(str));
if (tmp != NULL)
str = tmp;
This is not wrong, but it makes your code unnecessarily ugly, sizeof(char) is guaranteed to be 1.
Presumably strlength() emulates strlen(), so you don't want to compute the length twice, store it and use the value.
You allocate space the first time with malloc() but you drop that pointer completely because of the misuse of realloc() in your code, moreover you don't really need to allocate space except before writing to the pointed data, so you can replace your realloc() with malloc() and remove the calloc(), which by the way unnecessarily initialized all the values to 0, you don't need that.
You only initialize the last value of str which is set to '\0', but the rest of the data remains uninitialized because the function that would actually be allocating memory would be realloc() if it were used correctly, specially since calloc() is allocating a single byte.
Related
I'm attempting to read sequences from a FASTA file into a table of structs that I've created, which each contain a character array member called "seq". My code seems to work well for the first loop, but when I realloc() memory for the second sequence, the pointer seems to point to garbage values and then the strcat() method gives me a segfault.
Here's the whole FASTA file I'm trying to read from:
>1
AAAAAAAAAAGWTSGTAAAAAAAAAAA
>2
LLLLLLLLLLGWTSGTLLLLLLLLLLL
>3
CCCCCCCCCCGWTSGTCCCCCCCCCCC
Here's the code (sorry that some of the variable names are in french):
typedef struct _tgSeq { char *titre ; char *seq ; int lg ; } tgSeq ;
#define MAX_SEQ_LN 1000
tgSeq* readFasta(char *nomFile) {
char ligne[MAX_SEQ_LN];
tgSeq *lesSeq = NULL;
int nbSeq=-1;
FILE *pF = fopen(nomFile, "r");
while(fgets(ligne, MAX_SEQ_LN, pF) != NULL) {
if(ligne[0] == '>') {
/*create a new sequence*/
nbSeq++;
//reallocate memory to keep the new sequence in the *lesSeq table
lesSeq = realloc(lesSeq, (nbSeq)*sizeof(tgSeq));
//allocate memory for the title of the new sequence
lesSeq[nbSeq].titre = malloc((strlen(ligne)+1)*sizeof(char));
//lesSeq[nbSeq+1].titre becomes a pointer that points to the same memory as ligne
strcpy(lesSeq[nbSeq].titre, ligne);
//Now we create the new members of the sequence that we can fill with the correct information later
lesSeq[nbSeq].lg = 0;
lesSeq[nbSeq].seq = NULL;
} else {
/*fill the members of the sequence*/
//reallocate memory for the new sequence
lesSeq[nbSeq].seq = realloc(lesSeq[nbSeq].seq, (sizeof(char)*(lesSeq[nbSeq].lg+1+strlen(ligne))));
strcat(lesSeq[nbSeq].seq, ligne);
lesSeq[nbSeq].lg += strlen(ligne);
}
}
// Close the file
fclose(pF);
return lesSeq;
}
For the first line (AAAAAAAAAAGWTSGTAAAAAAAAAAA), lesSeq[nbSeq].seq = realloc(lesSeq[nbSeq].seq, (sizeof(char)*(lesSeq[nbSeq].lg+1+strlen(ligne)))); gives me an empty character array that I can concatenate onto, but for the second line (LLLLLLLLLLGWTSGTLLLLLLLLLLL) the same code gives me garbage characters like "(???". I'm assuming the problem is that the reallocation is pointing towards some sort of garbage memory, but I don't understand why it would be different for the first line versus the second line.
Any help you could provide would be greatly appreciated! Thank you!
The problem here is the first realloc gets the value of nbSeq as 0 which does not allocate any memory.
Replace
int nbSeq=-1;
with
int nbSeq=0;
Access the index with lesSeq[nbSeq - 1]
Some programmer dude already pointed out that you do not allocate enough memory.
You also seem to expect some behaviour from realloc that will not happen.
You call realloc with NULL pointers. This will make it behave same as malloc.
For the first line (AAAAAAAAAAGWTSGTAAAAAAAAAAA), ...= realloc(); gives me an empty character array that I can concatenate onto, but for the second line (LLLLLLLLLLGWTSGTLLLLLLLLLLL) the same code gives me garbage characters like "(???".
You should not expect any specifiy content of your allocated memory. Especially the memory location is not set to 0. If you want to rely on that, you can use calloc.
Or you simply assign a 0 to the first memory location.
You do not really concatenaty anything. Instead you allocate new memory where you could simply use strcpy instead of strcat.
I'm working on a program in C and one of my key functions is defined as follows:
void changeIndex(char* current_index)
{
char temp_index[41]; // note: same size as current_index
// do stuff with temp_index (inserting characters and such)
current_index = temp_index;
}
However, this function has no effect on current_index. I thought I found a fix and tried changing the last line to
strcpy(current_index, temp_index)
but this gave me yet another error. Can anyone spot what I'm doing wrong here? I basically just want to set the contents of current_index equal to that of temp_index at each call of changeIndex.
If more information is needed, please let me know.
strcpy should work if current_index points to allocated memory of sufficient size. Consider the following example, where changeIndex require additional parameter - size of distination string:
void changeIndex(char* current_index, int max_length)
{
// check the destination memory
if(current_index == NULL)
{
return; // do nothing
}
char temp_index[41];
// do stuff with temp_index (inserting characters and such)
// copy to external memory, that should be allocated
strncpy(current_index, temp_index, max_length-1);
current_index[max_length-1] = '\0';
}
Note: strncpy is better for the case when temp_index is longer then current_index.
Examples of usage:
// example with automatic memory
char str[20];
changeIndex(str, 20);
// example with dinamic memory
char * ptr = (char *) malloc(50);
changeIndex(ptr, 50);
Obviously defining a local char array on the stack and returning a pointer to it is wrong. You should never do that as the memory is not defined after the function ends.
In addition to the previous answers: The strncpy char pointer (which seems unsafe for my opinion), and the malloc which is safer but you need to remember to free it outside of the function (and its inconsistent with the hierarchy of the program) you can do the following:
char* changeIndex()
{
static char temp_index[41]; // note: same size as current_index
// do stuff with temp_index (inserting characters and such)
return temp_index;
}
As the char array is static it will not be undefined at the end of the function and you do not need to remember to free the pointer at the end of the use.
Caveat: If you are using multiple thread you cannot use this option as the static memory could be changed by different threads entering the function at the same time
Your array temp_index is local for function, then *current_index don't take what u want.
U can use also function strdup . Function return begin memory location of copied string , or NULL if error occurred, lets say ( char *strdup(char *) )
char temp[] = "fruit";
char *line = strdup(temp );
After running this function many (not sure exactly how many) times, it seg faults on a simple memory allocation. Why would this suddenly happen? I did notice something strange in GDB. In the function that calls it, normally there's 6-digit long hex value for wrd (wrd = 0x605140 for example), however on the call where it crashes, the hex value is only two digits long. (wrd=0x21). I also checked the wrd->length, and it's 3.
The line that it crashes on is...
char *word_temp = malloc(wrd->length * sizeof(char));
EDIT:
Here's the code that creates the wrd...
while(fgets(input, 100, src) != 0)
{
int i = 0;
while(input[i] != '\0')
{
i++;
}
struct word *wrd = malloc(sizeof(struct word));
wrd->letters = input;
wrd->length = i;
If I'm getting an overflow, how do I fix that?
Looks like wrd->length does not include the terminating '\0'.
Fix 1, allocate word_temp like this:
char *word_temp = malloc( wrd->length + 1 );
Fix 2, include the '\0' by modifying you length count loop:
int i = 0;
while(input[i++] != '\0') {}
This will increase i one more time than code in the question, which is easy to see if you consider case of input being empty.
Note that you need to do either fix 1 or fix 2, not both. Choose which ever works with rest of your code.
You probably have a second issue with this line:
wrd->letters = input;
It does not copy input, it copies the pointer. If you change contents of input, contents of wrd->letters changes too, because they point to same memory location. Also if input is a local char array, then once it goes out of scope, wrd->letters becomes a dangling pointer, which will be overwritten by other data, and modifying it after that will result in memory corruption.
Possible fix (depending on rest of your code) is to use strdup:
wrd->letters = strdup(input);
Remember that it is now allocated from heap, so when done, you must remember to do
free(wrd->letters);
About wrd being 0x21, that indicates either memory corruption, or that you actually have two separate wrd variables, and one one is left uninitialized.
For example, maybe wrd is a function parameter struct word *wrd, in which case you only modify the local value in function, it does not get passed back to the caller. To modify the pointer of caller, you need to have pointer to pointer: struct word **wrd and then do (*wrd) = malloc... and (*wrd)->letters... etc.
I am trying to use realloc function to store input characters in a dynamically array. Everything goes fine when I use it without calling free method to release the memory after usage. But when I use it with free method runtime error comes. Here is my code snippet.
int main(){
char *message ;
int len = 0 ;
char c ;
while((c=getchar()) != '\n'){
message = realloc(message,(len+1)*sizeof(char)) ;
message[len++] = c ;
}
message = realloc(message, (len+1)* sizeof(char));
message[len]='\0' ;
printf("Message is %s\n",message);
free(message) ;
return 0 ;
}
Can anyone figure out this. As i need to use both method together..
Thanks!!!!
Though it may not be causing the problem you're seeing, X = realloc(X, newsize); is a timebomb waiting to explode. realloc can return a null pointer and leave your existing data unchanged if it fails to allocate the new chunk you've asked for. When/if it does that, this will overwrite the existing pointer with NULL, leaking the memory you've previously allocated (and failing to allocate more).
Though it's probably not causing the problem either, I'd also recommend (strongly) against using realloc to increase your allocation one character at a time. That's horribly inefficient. I'd start with a block of, say, 32 or 64 characters, and increase the allocation by some factor (say, 1.5) each time you run out of space. This way you can deal with greatly different lengths of input without a huge number of calls to realloc.
Edit: looking at it, the real problem probably that you haven't initialized your pointer properly before the initial call to realloc. If you pass something other than a NULL pointer, it expects what you're passing to be a valid pointer you got from malloc/calloc or a previous call to realloc.
int main(){
char *message ;
int len = 0 ;
char c ;
while((c=getchar()) != '\n'){
message = realloc(message,(len+1)*sizeof(char)) ;
message[len++] = c ;
}
message = realloc(message, (len+1)* sizeof(char));
message[len]='\0' ;
printf("Message is %s\n",message);
free(message) ;
return 0 ;
}
At least for me, this runs without any error messages.
So I have a couple of functions that work with a string type I have created. One of them creates a dynamically allocated sting. The other one takes said string, and extends it. And the last one frees the string. Note: The function names are changed, but all are custom-defined by me.
string new = make("Hello, ");
adds(new, "everyone");
free(new);
The code above works - it compiles and runs fine. The code below does not work - it compiles, runs, and then
string new = make("Hello, ");
adds(new, "everyone!");
free(new);
The difference between the code is that the adds() function is adding 1 more character (a !). The character it adds makes no difference - just the length. Just for completeness, the following code does not work:
string new = make("Hello, ");
adds(new, "everyone");
adds(new, "!");
free(new);
Oddly, the following code, which uses a different function, addc() (which adds 1 character instead of a string) works:
string new = make("Hello, ");
adds(new, "everyone");
addc(new, '!');
free(new);
The following, which also does the same thing, works:
string new = make("Hello, everyone!");
free(new);
The error that all the ones that don't work give is this:
test(526) malloc: *** error for object 0x100130: double free
*** set a breakpoint in malloc_error_break to debug
(test is the extremely descriptive name of the program I have this in.)
As far as the function internals, my make() is a call to strlen() and two calls to malloc() and a call to memcpy(), my adds() is a call to strlen(), a call to realloc(), and a call to memcpy(), and my free() is two calls to the standard library free().
So are there any ideas why I'm getting this, or do I need to break down and use a debugger? I'm only getting it with adds()es of over a certain length, and not with addc()s.
Breaking down and posting code for the functions:
typedef struct _str {
int _len;
char *_str;
} *string;
string make(char *c)
{
string s = malloc(sizeof(string));
if(s == NULL) return NULL;
s->_len = strlen(c);
s->_str = malloc(s->_len + 1);
if(s->_str == NULL)
{
free(s);
return NULL;
}
memcpy(s->_str, c, s->_len);
return s;
}
int adds(string s, char *c)
{
int l = strlen(c);
char *tmp;
if(l <= 0) return -1;
tmp = realloc(s->_str, s->_len + l + 1);
if(!tmp) return 0;
memcpy(s->_str + s->_len, c, l);
s->_len += l;
s->_str[s->_len] = 0;
return s->_len;
}
void myfree(string s)
{
if(s->_str) free(s->_str);
free(s);
s = NULL;
return;
}
A number of potential problems I would fix:
1/ Your make() is dangerous since it's not copying across the null-terminator for the string.
2/ It also makes little sense to set s to NULL in myfree() since it's a passed parameter and will have no effect on the actual parameter passed in.
3/ I'm not sure why you return -1 from adds() if the added string length is 0 or less. First, it can't be negative. Second, it seems quite plausible that you could add an empty string, which should result in not changing the string and returning the current string length. I would only return a length of -1 if it failed (i.e. realloc() didn't work) and make sure the old string is preserved if that happens.
4/ You're not storing the tmp variable into s->_str even though it can change - it rarely re-allocates memory in-place if you're increasing the size although it is possible if the increase is small enough to fit within any extra space allocated by malloc(). Reduction of size would almost certainly re-allocate in-place unless your implementation of malloc() uses different buffer pools for different-sized memory blocks. But that's just an aside, since you're not ever reducing the memory usage with this code.
5/ I think your specific problem here is that you're only allocating space for string which is a pointer to the structure, not the structure itself. This means when you put the string in, you're corrupting the memory arena.
This is the code I would have written (including more descriptive variable names, but that's just my preference).
I've changed:
the return values from adds() to better reflect the length and error conditions. Now it only returns -1 if it couldn't expand (and the original string is untouched) - any other return value is the new string length.
the return from myfree() if you want to really do want to set the string to NULL with something like "s = myfree (s)".
the checks in myfree() for NULL string since you can now never have an allocated string without an allocated string->strChars.
Here it is, use (or don't :-) as you see fit:
/*================================*/
/* Structure for storing strings. */
typedef struct _string {
int strLen; /* Length of string */
char *strChars; /* Pointer to null-terminated chars */
} *string;
/*=========================================*/
/* Make a string, based on a char pointer. */
string make (char *srcChars) {
/* Get the structure memory. */
string newStr = malloc (sizeof (struct _string));
if (newStr == NULL)
return NULL;
/* Get the character array memory based on length, free the
structure if this cannot be done. */
newStr->strLen = strlen (srcChars);
newStr->strChars = malloc (newStr->strLen + 1);
if(newStr->strChars == NULL) {
free(newStr);
return NULL;
}
/* Copy in string and return the address. */
strcpy (newStr->strChars, srcChars);
return newStr;
}
/*======================================================*/
/* Add a char pointer to the end of an existing string. */
int adds (string curStr, char *addChars) {
char *tmpChars;
/* If adding nothing, leave it alone and return current length. */
int addLen = strlen (addChars);
if (addLen == 0)
return curStr->strLen;
/* Allocate space for new string, return error if cannot be done,
but leave current string alone in that case. */
tmpChars = malloc (curStr->strLen + addLen + 1);
if (tmpChars == NULL)
return -1;
/* Copy in old string, append new string. */
strcpy (tmpChars, curStr->strChars);
strcat (tmpChars, addChars);
/* Free old string, use new string, adjust length. */
free (curStr->strChars);
curStr->strLen = strlen (tmpChars);
curStr->strChars = tmpChars;
/* Return new length. */
return curStr->strLen;
}
/*================*/
/* Free a string. */
string myfree (string curStr) {
/* Don't mess up if string is already NULL. */
if (curStr != NULL) {
/* Free chars and the string structure. */
free (curStr->strChars);
free (curStr);
}
/* Return NULL so user can store that in string, such as
<s = myfree (s);> */
return NULL;
}
The only other possible improvement I could see would be to maintain a buffer of space and the end of the strChars to allow a level of expansion without calling malloc().
That would require both a buffer length and a string length and changing the code to only allocate more space if the combined string length and new chars length is greater than the buffer length.
This would all be encapsulated in the function so the API wouldn't change at all. And, if you ever get around to providing functions to reduce the size of a string, they wouldn't have to re-allocate memory either, they'd just reduce their usage of the buffer. You'd probably need a compress() function in that case to reduce strings that have a large buffer and small string.
The first malloc in make should be:
malloc (sizeof (struct _str));
Otherwise you're only allocating enough space for a pointer to struct _str.
tmp = realloc(s->_str, s->_len + l + 1);
realloc can return a new pointer to the requested block. You need to add the following line of code:
s->_str = tmp;
The reason it doesn't crash in one case but does after adding one more character is probably just because of how memory is allocated. There's probably a minimum allocation delta (in this case of 16). So when you alloc the first 8 chars for the hello, it actually allocates 16. When you add the everyone it doesn't exceed 16 so you get the original block back. But for 17 chars, realloc returns a new memory buffer.
Try changing add as follows
tmp = realloc(s->_str, s->_len + l + 1);
if (!tmp) return 0;
if (tmp != s->_str) {
printf("Block moved!\n"); // for debugging
s->_str = tmp;
}
In function adds, you assume that realloc does not change the address of the memory block that needs to be reallocated:
tmp = realloc(s->_str, s->_len + l + 1);
if(!tmp) return 0;
memcpy(s->_str + s->_len, c, l);
While this may be true for small reallocations (because sizes of blocks of memory you get are usually rounded to optimize allocations), this is not true in general. When realloc returns you a new pointer, your program still uses the old one, causing the problem:
memcpy(s->_str + s->_len, c, l);
Probably should post the code, but the double free means you are calling free on the same pointer twice.
Are you adding 1 to strlen for the \0 byte at the end?
Once you free a pointer, are you setting your member variable to NULL so that you don't free again (or to a known bad pointer like 0xFFFFFFFF)
Why does "my free() is two calls to the standard library free()." Why are you calling free twice? You should only need to call once.
Please post your adds(); and free() functions.