I need to make a function that takes a string and a character, the function needs to remove all the occurrences of the character in the string and returns the total number of characters removed. I have managed to modify the string as to be able to remove the unwanted character but I can't seem to be able to replace the old string with the new one. Thanks for any replies in advance.
This is what I've managed so far:
int clearstr(char *st,char u){
int i,j=0,total=0,size=strlen(st);
char *new_str=calloc(size,sizeof(char));
for(i=0;i<size;i++){
if(st[i]!=u){
new_str[j]=st[i];
j++;}
else total++;
}
new_str[j]='\0';
printf("%s",new_str);
//until here all is good ,new_str has the modified array that i want but i can't find a way to replace the string in st with the new string in new_str and send it back to the calling function (main),thanks for any help //
return total;
}
You create a new string but you are not using it yet. You can use a function like memcpy or strcpy to copy the contents. You also don't deallocate the memory of the calloc call; this creates a memory leak. Try something like:
...
new_str[j]='\0';
printf("%s",new_str);
strcpy(st, new_str); // Copy the contents of the new string to the original one
free(new_str); // Clear the memory of the allocation in this function, otherwise you get a memory leak
return total;
...
Related
I'm trying to make a function that goes through a linked list and finds all strings that contain a substring that the user inputs.
The problem is that its case sensitive and I need it to not be.
My idea was to make everything lowercase while going through the list. And wrote something that should work... I think... but doesn't
char *lowerCase(char* strToLower){
char *lowCase;
strcpy(lowCase, strToLower);
for(int i = 0; lowCase[i]; i++){
lowCase[i] = tolower(lowCase[i]);
}
return lowCase;
}
printf("%s", lowerCase("Name"));
Now, what ideally should pop up is "name", but I instead get nothing.
I get Process returned -1073741819 (0xC0000005), which I think is an error related to pointers or memory? I don't really know because build log doesn't tell me anything.
Any help is appreciated <3
The Problem is that you use strcpy wrong. Please refer to the manpage: https://linux.die.net/man/3/strcpy
You need to actually allocate a buffer for the copied string. You right now just copy it to a random memory location (as lowCase is not initialized).
You need to so:
char *lowerCase(char* strToLower){
char *lowCase = (char *)malloc(strlen(strToLower) + 1); // +1 because of terminator
strcpy(lowCase, strToLower);
for(int i = 0; lowCase[i]; i++){
lowCase[i] = tolower(lowCase[i]);
}
return lowCase;
}
and it should work. But beware: As lowCase was allocated, you also need to free it after use, otherwise you have a memory leak.
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 trying to hunt down memory leaks and have found one source. I am malloc'in the pointer in one function and freeing it in another, but I'm missing out on understanding how to copy the value the pointer points to while also being able to free the pointer.
Current implementation (with memory leak):
// This code has been greatly simplified
// and as such does not appear to have any purpose
int foo(){
int bestval = 0;
char *best;
char *match;
for (int i=0;i<3;i++) {
int returnValue = bar(&best);
if (returnValue > 10) {
(1)
match = best;
}
}
printf("%s", match);
(2)
return 0;
}
int bar(char ** best) {
char*s = "Hello!";
*best = malloc(strlen(s) + 1);
strcpy(*best,s);
return 0;
}
Two questions
If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?
A bit of a stab in the dark, assuming there's a loop in Foo...
int foo()
{
int bestval = 0;
char *best;
char *match = 0; // initialize to null
// start some loop
for (int i=0;i<3;i++) {
// fetch the next best value...
int returnValue = bar(&best);
// some check (if best is really best!)
if (returnValue > 10) {
// if match has previously been populated, free it
if(match) {
free(match);
}
// save the new best value
match = best;
}
else {
// not saving best in match, so free it!
free(best);
}
}
// end some loop
// only do this if match was successful?!?
if(match) {
printf("%s", match);
// clean up once the best of the best has been used...
free(match);
}
return 0;
}
In function bar the strcpy should read as
strcpy(*best,s);
In the main function you can copy the value best points to by
strcpy(match, best);
free(best);
match needs to point to a valid memory block before. If you do a
match = best;
free(best);
match will be invalid too because it points at the same freed memory best pointed.
You need to know the size of the string.
At (1) You would be assigning the address of a memory address that has already been freed, you have to do another malloc to match*=malloc(sizestr) and then copy it with memmove or strcpy if you want to free best.
If I understood properly, you want to copy the string into best, then free bests memory and assign ptr to match? if you free best memory before memmoving or strcpying to another location you lose its contents, and if you want to copy it to another location first you need to allocate the memory where you want to copy it to, so you need 2 mallocs on that code.
If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
If you free at position (1), it is not possible to do it so that match would still have what was contained in best.
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?
match = best;
With the above statement, both are pointing to the same location. So, there is no need to strcpy at all. To do that, allocate memory for match to point to whose length is best+1 and then do a strcpy.
Copying the value of a pointer does not copy the underlying memory. So either, don't free(best) until you are done with match, or you will need to malloc a new buffer, and e.g. memcpy() the contents from one buffer to the other.
Yes, you can malloc and strcpy:
match = malloc(strlen(best) + 1);
strcpy(match, best);
But, if your implementation provides it you can use the strdup() function which is much easier:
match = strdup(best);
If you don't already have strdup(), it's a good idea to create one yourself.
Your current assignment simply assigns the pointers to the same buffer. If you then free() this buffer, you've removed what is contained here (and thus dereferencing it is a bad idea).
You don't need to use strcpy() to copy best to match - you'll be better off freeing it after the printf() (or the last point that it is needed). There's no point over-complicating things with an extra function call or six, just remember to free() memory that you've allocated at the end of each function!
How do I return an array of strings from a recursive function?
For example::
char ** jumble( char *jumbStr)//reccurring function
{
char *finalJumble[100];
...code goes here...call jumble again..code goes here
return finalJumble;
}
Thanks in advance.
In C, you cannot return a string from a function. You can only return a pointer to a string. Therefore, you have to pass the string you want returned as a parameter to the function (DO NOT use global variables, or function local static variables) as follows:
char *func(char *string, size_t stringSize) {
/* Fill the string as wanted */
return string;
}
If you want to return an array of strings, this is even more complex, above all if the size of the array varies. The best IMHO could be to return all the strings in the same string, concatenating the strings in the string buffer, and an empty string as marker for the last string.
char *string = "foo\0bar\0foobar\0";
Your current implementation is not correct as it returns a pointer to variables that are defined in the local function scope.
(If you really do C++, then return an std::vector<std::string>.)
Your implementation is not correct since you are passing a pointer to a local variable that will go out of scope rather quickly and then you are left with a null pointer and eventually a crash.
If you still want to continue this approach, then pass by reference (&) an array of characters to that function and stop recursing once you have reached the desired end point. Once you are finished, you should have the 'jumbled' characters you need.
You don't :-)
Seriously, your code will create a copy of the finalJumble array on every iteration and you don't want that I believe. And as noted elsewhere finalJumble will go out of scope ... it will sometimes work but other times that memory will be reclaimed and the application will crash.
So you'd generate the jumble array outside the jumble method:
void jumble_client( char *jumbStr)
char *finalJumble[100];
jumble(finalJuble, jumbStr);
... use finalJumble ...
}
void jumble( char **jumble, char *jumbStr)
{
...code goes here...call jumble again..code goes here
}
And of course you'd use the stl datatypes instead of char arrays and you might want to examine whether it might be sensible to write a jumble class that has the finalJumble data as a member. But all that is a little further down the road. Nevertheless once you got the original problem solved try to find out how to do that to learn more.
I would pass a vector of strings as a parameter, by reference. You can always use the return value for error checking.
typedef std::vector<std::string> TJumbleVector;
int jumble(char* jumbStr, TJumbleVector& finalJumble) //recurring function
{
int err = 0; // error checking
...code goes here...call jumble again..code goes here
// finalJumble.push_back(aGivenString);
return err;
}
If you want to do it in C, you can keep track of the number of strings, do a malloc at the last recursive call, and fill the array after each recursive call. You should keep in mind that the caller should free the allocated memory. Another option is that the caller does a first call to see how much space he needs for the array, then does the malloc, and the call to jumble:
char** jumble(char* jumbStr)
{
return recursiveJumble(jumbStr, 0);
}
char** recursiveJumble(char* jumbStr, unsigned int numberOfElements)
{
char** ret = NULL;
if (/*baseCase*/)
{
ret = (char**) malloc(numberOfElements * sizeof(char*));
}
else
{
ret = jumble(/*restOfJumbStr*/, numberOfElements+1);
ret[numberOfElements] = /*aGivenString*/;
}
return ret;
}
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.