segfault when freeing a pointer during string reversing in C - c

int main(int argc, char **argv){
char *str = argv[1];
size_t len = strlen(str);
char *dst = calloc(len+1, sizeof(char));
int i;
for(i=len-1; i>=0; i--){
memcpy(dst, str+i, 1);
dst++;
}
*(++dst) = '\0';
printf("%s\n", dst);
free(dst);
return 0;
}
Error checking omitted for more readability
I don't understand why i got a segfault with this message: "glibc free(): invalid pointer:"
I'm trying to write a small program that reverse a string using pointers but:
1) the last printf print nothing;
2) i got a segfault

You have:
char *dst = calloc(len+1, sizeof(char));
/* ... */
*(++dst) = '\0';
/* ... */
free(dst);
You must free the pointer that was allocated by malloc / calloc. Here you modified it. Make a copy of it so you can free it after.

the problem is you are changing the pointer in the calculations.
try use a temp or original for that like:
int main(int argc, char **argv){
char *str = argv[1];
size_t len = strlen(str);
char *dst = calloc(len+1, sizeof(char));
char *origDst = dst;
int i;
for(i=len-1; i>=0; i--){
memcpy(dst, str+i, 1);
dst++;
}
*(dst) = '\0';
printf("%s\n", origDst);
free(origDst);
return 0;
}

There are 2 points to be considered. One, is to make a copy of the original pointer allocated by calloc as shared by ouah already. Another point is to eliminate the increment of the pointer when NULL is stored i.e. *(++dst) = '\0'; should be *dst = '\0';. With these 2 changes, I am able to run your program without any issues.

Related

cast a char into a char* in C

I have a char array s[11]="0123456789"; and I want to be able to take each digit s[i](using a for loop) and cast it somehow to a char*(I need a char* specifically because I need to use strncat on some other string)
I've been trying to do this for the past 4 hours and I couldn't get anything done.
Unless you're willing to temporarily modify s, or copy the character somewhere else... You're going to have a hard time.
Modify s temporarily.
int main() {
char s[11] = "0123456789";
for (int i = 0; i < strlen(s); i++) {
// Modify s in place.
const char tmp = s[i+1];
s[i+1] = '\0';
char *substr = &s[i];
// Do something with substr.
printf("%s\n", substr);
// Fix s
s[i+1] = tmp;
}
}
Or copy s[i] to a new string.
int main() {
char s[11] = "0123456789";
for (int i = 0; i < strlen(s); i++) {
// Create a temporary string
char substr[2];
substr[0] = s[i];
substr[1] = '\0';
// Do something with substr.
printf("%s\n", substr);
}
}
Or maybe just don't use strncat?
Assuming you're actually using strncat or similar... Those functions are pretty trivial, especially if you are appending only a single character. You might just create your own version.
void append_character(char *buffer, int buffer_size, char new_character) {
int length = strlen(buffer);
if (length + 2 < buffer_size) {
buffer[length] = new_character;
buffer[length+1] = '\0';
} else {
// No space for an additional character, drop it like strncat would.
}
}
Or you could do it as a simple wrapper around strncat:
void append_character(char *buffer, int buffer_size, char new_character) {
char new_string[2] = { new_character, '\0' };
strncat(buffer, buffer_size, new_string);
}
What you are requesting does not make any sense. A char is a small number. A pointer is the address of some memory. Converting a char to a pointer won't give you a valid pointer, but a pointer that will crash as soon as it is used.
For strncat, you need an array of characters containing a C string. You could create a string by writing char array[2]; (now you have an array with space for two characters), then array[0] = whateverchar; array[1] = 0; and now you have a C string with space for exactly one char and one trailing zero byte.
Yet another idea:
#include <stdio.h>
#include <string.h>
int main(void)
{
char src[11]="0123456789";
char dest[50]="abc";
char* p = src;
int i = 0;
int len = strlen(src);
for (i = 0; i < len; i++)
{
strncat(dest,p,1);
p++;
}
printf("src: %s\n", src);
printf("dest: %s\n", dest);
return 0;
}
Compiled with gcc under Ubuntu:
$ gcc hello_str.c -o hello_str
Output:
$ ./hello_str
src: 0123456789
dest: abc0123456789

Why malloc can't work with strcpy?

char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}else{
printf("Error");
}
return copy;
}
int main(int argc, char * argv[]){
char str[] = "Input string";
char * input;
input = removeChar(str,'g');
printf("%s\n", input);
free(input);
return 0;
}
I don't know why every time I try to run it ,it always says uninitialized variable and sticks in the strcpy line and printf line.
Basically this function is to take a string, and a character and removes the that character from the string (because I am learning malloc so that's why I wrote the function like this).
After the while loop do:
copy[j] = '\0';
to NULL-terminate your string; that way it can work with methods coming from <string.h>, which assume that the string is nul-terminated.
PS: One warning you should see is about not returning copy in your function in any case, because now if the condition of the if statement is wrong, your function won't return something valid, so add this:
return copy;
at the end of your function (which is now corrected with your edit).
Other than that, the only warning you should still get are for the unused arguments of main(), nothing else:
prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
While you copy over bytes from str to copy, you don't add a terminating null byte at the end. As a result, strcmp reads past the copied characters into unitialized memory, possibly past the end of the allocated memory block. This invokes undefined behavior.
After your while loop, add a terminating null byte to copy.
Also, you never return a value if the if block at the end is false. You need to return something for that, probably the copied string.
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
// add terminating null byte
copy[j] = '\0';
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}
// always return copy
return copy;
}
You never initialised input and the some compilers don't notice,
that the the value is never used before the line
input = removeChar(str, 'g');
in your code. So they emit the diagnostic just to be sure.
strcpy(str, copy)
gets stuck in your code, as copy never got a closing 0 byte and
so depends on the nondeterministic content of your memory at the
moment of the allocation of the memory backing copy, how long strcpy
will run and if you get eventually a SIGSEGV (or similar).
strcpy will loop until it finds a 0 byte in your memory.
For starters to remove a character from a string there is no need to create dynamically a character array and then copy this array into the original string.
Either you should write a function that indeed removes the specified character from a string or a function that creates a new string based on the source string excluding the specified character.
It is just a bad design that only confuses users. That is the function is too complicated and uses redundant functions like malloc, strlen, strcmp and strcpy. And in fact it has a side effect that is not obvious. Moreover there is used incorrect type int for the length of a string instead of the type size_t.
As for your function implementation then you forgot to append the terminating zero '\0' to the string built in the dynamically allocated array.
If you indeed want to remove a character from a string then the function can look as it is shown in the demonstrative program.
#include <stdio.h>
char * remove_char(char *s, char c)
{
char *p = s;
while (*p && *p != c) ++p;
for ( char *q = p; *p++; )
{
if (*p != c) *q++ = *p;
}
return s;
}
int main( void )
{
char str[] = "Input string";
puts(str);
puts(remove_char(str, 'g'));
return 0;
}
The program output is
Input string
Input strin
If you are learning the function malloc and want to use it you in any case should try to implement a correct design.
To use malloc you could write a function that creates a new string based on the source string excluding the specified character. For example
#include <stdio.h>
#include <stdlib.h>
char * remove_copy_char(const char *s, char c)
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p != c) ++n;
}
char *result = malloc(n + 1);
if (result)
{
char *q = result;
for (; *s; ++s)
{
if (*s != c) *q++ = *s;
}
*q = '\0';
}
return result;
}
int main( void )
{
char *str = "Input string";
puts(str);
char *p = remove_copy_char(str, 'g');
if ( p ) puts(p );
free(p);
return 0;
}
The program output will be the same as above.
Input string
Input strin
Pay attention to the function declaration
char * remove_copy_char(const char *s, char c);
^^^^^^
In this case the source string can be a string literal.
char *str = "Input string";

Modifying a char* by pointer in a function gives a crash

I'm fairly new to C and I'm trying to work out dynamic memory allocation for reading from a file. At least I think that's what I'm doing.
Anyway, this code works:
int readfromfile(FILE *filepointer)
{
size_t size = 2;
char *str = (char *) malloc(sizeof(char));
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
str = (char *) realloc(str, size);
str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", str);
free(str);
return 0;
}
And this code does not:
int main()
{
char *str = (char *) malloc(sizeof(char));
...
readfromfile(ifpointer, &str);
}
int readfromfile(FILE *filepointer, char **str)
{
size_t size = 2;
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
*str = (char *) realloc(*str, size);
*str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", *str);
free(str);
return 0;
}
I cannot understand why because as far as I understand I'm sending a pointer to the location of the char array to the function and accessing the data everytime. The compilers shows no error messages, it just loops through once and on the second loop crashes after the realloc every time. The character assigned to the first value is garbage too.
I have spent an age trying to get this to worked and done a lot of research so I apologise if I've missed a solution but I'm truly stuck at this point.
You get a crash because
*str[counter] = (char) character;
is the same as
*(str[counter]) = (char) character;
as opposed to
(*str)[counter] = (char) character;
which is actually what you wanted. Read Operator Precedence on Wikipedia. You'll find that [] has more precedence than the * (dereference operator).
Also, the cast here, as well as in the calls to realloc and malloc, is unnecessary. Don't forget to check the return value of realloc, malloc etc to see if they were successful in allocating memory.
Now, you have another problem: free(str); in the second code should be free(*str);. Note that after *str has been freed from the function, you aren't supposed to read or write into this memory location from main as it has now become invalid for you to tamper with.
in your int readfromfile(FILE *filepointer, char **str) the parameter char **str is actually the same as char *str[], which means **str is expecting an array of char pointers. however you're passing to it char *str which is just an array of char
when you use readfromfile(...) you should do it this way (something like...):
char *str[2] = {"some char array", "another char array"};
readfromfile(ifpointer, str);
or:
char *a = "this char array";
char **str = &a[0];
readfromfile(ifpointer, str);
you'll get the idea...

copying a string to another string in C

char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source) +1;
char *dest = (char*)malloc(sizeof(char)*len);
while(*source != '\0')
{
// dest[ii++] = *source++;
*dest++ = *source++;
}
// dest[ii] = '\0';
*dest = '\0';
printf("\n copied string = %s", dest1);
return dest;
}
I want to copy source string to destination string.
The above api is returning null.
If I use array of character (this I have commented) then this api works to me.
Please help me to understand the difference between
dest[ii++] = *source++
and
*dest++ = *source++;
You're incrementing dest during the while loop. You need to keep hold of a pointer to the start of the buffer to return from the function.
char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source);
char *copy = malloc(len+1);
char* dest = copy;
while(*source != '\0')
{
*dest++ = *source++;
}
*dest = '\0';
printf("\n copied string = %s", copy);
return copy;
}
Note that you could save some code by using strcpy
char *stringcopywithpointer( const char *source)
{
int len = strlen(source);
char *copy = malloc(len+1);
strcpy(copy, source);
return copy;
}
and you could reduce this to a single line if you have access to the non-standard strdup
char *stringcopywithpointer( const char *source)
{
return strdup(source);
}
My opinion:
Avoid allocate memory in called function, better allot memory before calling a function
char *dest = ( char* ) malloc( sizeof( char ) * len ); // doesn't looks great
Irrespective of the machine, sizeof( char ) is always 1 byte. Less redundant is sizeof( char ) * len. Optimal would be malloc( sizeof( source ) ).
Pointers and arrays are related
You can either use
dest[i] = src[i];
*dst++ = *src++;
or
// assuming dst memory allocate by caller
while ( *dst++ = *src++);
1)
printf("\n copied string = %s", dest1);
should be
printf("\n copied string = %s", dest);
This could be a typo
2)
You can change:
while(*source != '\0')
{
*dest++ = *source++;
}
by
while(*dest++ = *source++);
3)
Concerning difference between dest[ii++] = *source++ and *dest++ = *source++;
There is no difference and should work if dest is defined in this way
char *dest = (char*)malloc(sizeof(char)*len);
If your array is define in this way:
char dest[len];
Then there is difference
You should not return an allocated string. This can easily lead to a memory leak.
Instead you should consider passing allocated memory into your function to copy it.
You can use your return value to return an error if anything went wrong.
This would change your signature to.
int stringcopywithpointer( char * dest, const char *source)
to make your code a little bit more versitile you could implement vargs and your signature would be:
int stringcopywithpointerf( char * dest, const * format, ... );
This is actually the already existing function sprintf.
int sprintf( char * dest, const * format, ... );
There are also secure variants of the function available and premade. You may want to consider using one of those.
If this is homework related take a look at this function:
char * myscpy(const char * SRC){
size_t size = strlen( SRC ) + 1 ;
char * START;
char * DST = ( char * ) malloc( size );
START = DST;
do
{
*DST = *SRC;
DST++;
SRC++;
}while( *SRC != 0 );
*DST = *SRC;
return START;
}
You likely want to add errorchecks to it like you had them in place (malloc etc.) in your original post.
"Please help me to understand the difference between dest[i++] and *dest++"
dest[i++] does not increment the pointer but the index to the pointer.
*dest++ increments the pointer after its original contendt was accessed.
Add char *dest1 = dest; right after malloc and then return dest1 and that will work.
Other possible change: replace while loop with post-condition loop (i.e. copy the zero byte first, then check if it was the end).
may be you need to add this line
char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source) +1;
char *ptr = NULL;
char *dest = (char*)malloc(sizeof(char)*len);
/** No Error Checking for malloc is a strict no no **/
if(dest == NULL)
return NULL;
/** hold the dest adress in ptr as we are incrementing dest **/
ptr = dest;
while(*source != '\0')
{
// dest[ii++] = *source++;
*dest++ = *source++;
}
// dest[ii] = '\0';
*dest = '\0';
//printf("\n copied string = %s", dest1); ??
printf("\n copied string = %s", ptr); // ptr will have our copied String
/** so return ptr not dest **/
return ptr;
}

Function is not printing out the result

I have to make a function which concatenates two strings but I have to add a '\n' after the first word. I figured everything out and for some reason it doesn't print out anything. Any ideas? It probably has to do something with the pointers. I just can't get my head around them. Here's the code.
char *function(char *s1, char *s2){
char *newStr;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *)malloc((size+1)*sizeof(char));
while(*s1!= '\0'){
*newStr = *s1;
newStr++;
s1++;
}
*newStr = '\n';
newStr++;
while(*s2 != '\0'){
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return newStr;
}
int main (int argc, const char * argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s",function(str1, str2));
return 0;
}
So as a result I should get:
Hello
World
but I'm not getting anything back.
You are returning a pointer to the end of the buffer rather than a pointer to the start of the buffer. Look at the last two lines of the function:
*newStr = '\0';
return newStr;
Clearly this returns a pointer to the null char, i.e. the empty string.
Solve the problem by introducing a temporary pointer which you will use to step through the output buffer. Then you can return the pointer to the beginning of the output buffer.
char *function(char *s1, char *s2){
int size = strlen(s1) + strlen(s2) + 2;//one for '\n', one for '\0'
char *result = malloc(size);
char *p = result;
while(*s1 != '\0'){
*p = *s1;
p++;
s1++;
}
*p = '\n';
p++;
while(*s2 != '\0'){
*p = *s2;
p++;
s2++;
}
*p = '\0';
return result;
}
You also need to allocate an extra char for the \n, as shown above. Finally, your calling code never frees the memory allocated by function.
I would take a look at two things:
how much space you're allocating for the new string, and compare that with how many characters you're actually writing to that string.
where in the string your returned pointer is pointing to.
You return from function() a pointer to the last element in the allocated char[] – instead of returning the pointer to the first element.
Every time you do newStr++; you increase the actual pointer you later return. to solve it you can do one of these:
create a copy of the pointer newStr, which is initialized to be the same as newStr and increase it - leave newStr as it is.
create an index [let it be i] and increase it, and use newStr[i] to access the allocated array.
I have debugged the code for you. Here is the debugged code:
char *function(char *s1, char *s2) {
char *newStr, *str;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *) malloc((size + 2) * sizeof(char));
str = newStr;
while (*s1 != '\0') {
*(newStr++) = *(s1++);
}
*newStr = '\n';
newStr++;
while (*s2 != '\0') {
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return str;
}
int main(int argc, const char *argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s", function(str1, str2));
return 0;
}
The actual problem was that as you incremented newStr until the last, when you returned it from function() it was pointing to the end of the buffer. ie '\0'. That is why it didn't show up. Now In the above code I have introduced a variable str that points at the beginning of the string newStr.
Hope you understood..
Peace...

Categories

Resources