Why does this return no warnings? What is supposed to be wrong with the code?
char *str = malloc(strlen("hello" + 1));
strcpy(str, "hello");
Thanks!
Why would you expect warnings?
The code is broken because you should be doing strlen("hello") + 1, not strlen("hello" + 1) (which is equivalent to strlen("ello")).
This
char *str = malloc(strlen("hello" + 1));
strcpy(str, "hello");
is nearly equivalent to:
char *temp = "hello";
char *temp2 = temp + 1;
char *str = malloc(strlen(temp2));
strcpy(str, "hello");
so temp + 1 is pointer math (it returns a pointer to ello, and strcpy doesn't check if enough memory is present at destination ("standard" memory corruption caused by faulty code in C)
The end result is that strlen returns 4, strcpy uses 6 bytes of memory and a random piece of heap is trashed.
The below statement is incorrect.
char *str = malloc(strlen("hello" + 1));
It should be
char *str = malloc(strlen("hello") + 1);
strlen in this case would probably return you a value of 4 instead of 5 and strcpy will lead to Out of Bounds write. Execute the program with a memory analyzer and it shall point out an error to you.
Related
The problem should be simple, but I have spent hours on this and cannot see what is wrong in my logic. The output works as it should, but Valgrind prints memory issues that should be fixed. I have added the origdest = (char*)realloc(origdest, strlen(origdest) + i * sizeof(char)); code to the while loop, my question is why doesn't this dynamically adjust the memory? The exact error given by Valgrind is
==9== Invalid write of size 1
==9== at 0x1087E2: mystrcat (mystrcat.c:18)
==9== by 0x10883C: main (mystrcat.c:34)
==9== Address 0x522d046 is 6 bytes inside a block of size 7 free'd
==9== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9== by 0x1087C2: mystrcat (mystrcat.c:17)
==9== by 0x10883C: main (mystrcat.c:34)
==9== Block was alloc'd at
==9== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9== by 0x108811: main (mystrcat.c:31)
char *mystrcat(char *dest, const char *src)
{
char *origdest = dest;
while(*dest) {
dest++;
}
int i = 1;
while (*src) {
origdest = (char*)realloc(origdest, strlen(origdest) + i * sizeof(char));
*dest++ = *src++; // Copies character and increases/moves pointer
i++;
}
*dest = 0;
return origdest;
}
int main(void)
{
char *str = malloc(7);
strcpy(str, "Mydogs");
str = mystrcat(str, "arecool");
printf("%s\n", str);
free(str);
}
This statement:
Address 0x522d046 is 6 bytes inside a block of size 7 free'd is saying that the realloc() called following these statements results in the old pointer pointing to freed memory.
after this segment:
char *origdest = dest;
while(*dest) {
dest++;
}
EDIT to address comment "what is specifically wrong with the code and what could be changed to make it work?"
The explanation of my first observation above is that once the pointer to allocated memory is moved, as you have done, the memory allocation tables no longer have an accurate location of that memory, making that memory un-freeable.
Your stated goal here is to create a version of strcat(), so using realloc() is a reasonable approach, but to use it safely allocate the new memory into a temporary buffer first, then if allocation fails, the original memory location still exists, and can be freed.
One other small change that makes a big difference is how i is initialized. If 1 is used, it places the beginning of the second string one extra position further in memory, leaving a \0 character just after the first string, effectively making it the end of the resultant string. i.e. you would never see the appended part of the string:
In memory it would look like this:
|M|y|d|o|g|s|\0|a|r|e|c|o|o|l|
Then over-flow your buffer when attempting to place another NULL terminator at the and of the concatenated buffer, resulting in undefined behavior.
The following adaptation of your code illustrates these, along with some other simplifications:
char *mystrcat(char *dest, const char *src)
{
char *temp = NULL;
int i = 0;//changed from i = 1 as first location to
//copy to is len1, not len1 + 1
//Note, starting at len1 + 1 would leave a NULL character
//after "Mydogs", effectively ending the string
//the following are simplifications for use in realloc()
int len1 = strlen(dest);
int len2 = strlen(src);
//call once rather than in a loop. It is more efficient.
temp = realloc(dest, len1+len2+1);//do not cast return of realloc
if(!temp)
{
//handle error
return NULL;
}
dest = temp;
while(*src)
{
dest[len1 + i] = *src;
i++;
src++;
}
dest[len1 + i] = 0;//add null terminator
return dest;
}
int main(void)
{
char *temp = NULL;
char *str = malloc(7);
if(str)//always a good idea to test pointer before using
{
strcpy(str, "Mydogs");
temp = mystrcat(str, "arecool");
if(!temp)
{
free(str);
printf("memory allocation error, leaving early");
return 0;
}
str = temp;
printf("%s\n", str);
free(str);
}
return 0;
}
Why it is not correct to cast the return of c-m-realloc() in C.
Here you move to the end of the original string:
while(*dest)
dest++;
Here you allocate some new memory, but dest still points to the end of the original string. So you are overwriting memory after the end of the original string. Since you are reallocating, the original string may not even exist anymore at the previous location you are writing to, because realloc can move the data to a completely new location.
while (*src)
{
origdest = (char*)realloc(origdest, strlen(origdest) + i * sizeof(char));
*dest++ = *src++; // Copies character and increases/moves pointer
i++;
}
I use *ptr to iterate a char array from end to beginning (one byte at the time) and set some values in the way. When the pointer points to the first address the algorithm should stop.
char *buf = (char*)malloc(sizeof(char) * 3 + 1);
char *ptr = &buf[sizeof buf - 1]; // *ptr point to the last address
*ptr = '\0';
do {
if(alfa) {
*(--ptr) = "teststring"[alfa]; // *ptr decreases value by one
alfa -= i;
} else { *(--ptr) = 'N'; }
} while(*ptr != &buf[0]); // should check if *ptr is now pointing to the start of buf. If that's the case, stop.
But, after it check the addresses are equal, it gives me:
** stack smashing detected **: <unknown> terminated
Aborted (core dumped)
Another (and maybe relatable) thing is: malloc should allocate 4 bytes from memory, but when I check sizeof(buf) it has 8 bytes(?).
Note: The output of sizeof(char) * 3 + 1 is indeed 4. But it's not the same as sizeof(buf).
sizeof some_variable evaluates to the size of a variable.
So this sizeof buf evaluates to the size of buf. With buf being a pointer it gives you either 4 or 8 depending whether the code is compiled on a 32 or 64 bit platform.
To fix your problem change this
char *buf = (char*)malloc(sizeof(char) * 3 + 1);
char *ptr = &buf[sizeof buf - 1];
to this
size_t size = sizeof(char) * 3 + 1;
char *buf = malloc(size); /* No need to cast void-pointer sin C. */
char *ptr = &buf[size - 1]; // *ptr point to the last address
Taking into account that sizeof (char) equals 1 by definition just do:
size_t size = 3 + 1;
char *buf = malloc(size);
char *ptr = &buf[size - 1];
The first answer is right, but also, your last test:
while(*ptr != &buf[0]);
Isn't checking that ptr is not at the first position in the buffer. That would be ptr != &buf[0] or just ptr != buf.
You are seeing if the data at pointer (*ptr) is unequal to the the location of the beginning of the buffer, thereby comparing a char to a pointer. Your compiler is probably giving you a warning about it. Don't ignore warnings in C.
Implement the append function that has the prototype below. The function returns a string that represents the concatenation of all the strings present in an array of strings. For this problem, you can assume the end of the parameter array is marked by NULL. You need to allocate memory for the resulting string. You may not modify the array parameter.
char* append(char *data[]);
I don't understand how to determine the size to malloc the pointer.
First of all, to know the size of one string, you can use strlen from the library string.h. If you want to calculate the sum of all the sizes you can just use a loop and sum up all the strlens, and add 1 for the terminal NUL character, like this:
char* append(char *data[]) {
char **cur, *res;
size_t len = 0;
for (cur = data; *cur != NULL; *cur++)
len += strlen(*cur);
res = malloc(len + 1);
// Now you can concatenate the strings...
}
Oh, and don't forget to check that the pointer returned by malloc is valid (i.e. not NULL).
An approach that goes through the strings twice seems good.
The first pass counts the sum of the lengths:
size_t len = 0;
for (char** pstr = data; *pstr; pstr++)
len += strlen(*pstr);
The second pass concatenates all the strings:
char *str = malloc(len + 1);
str[0] = '\0';
for (char** pstr = data; *pstr; pstr++)
strcat(str, *pstr);
return str;
You can optimize the concatenation part by storing the end point of the last concatenation:
char *str = malloc(len + 1);
str[0] = '\0';
char *p = str;
for (char** pstr = data; *pstr; pstr++) {
strcat(p, *pstr);
p += strlen(*pstr);
}
this is one of the question from 295c
#include<stdio.h>
#include<string.h>
main()
{
char *a="kammo DJ";
const char *b="roomies!!";
char *c;
a=(char *)malloc(strlen(a) + strlen(b));
c=(char *)malloc(strlen(a) + strlen(b));
c=strcat(a,b);
printf("%s\n",a);
}
and the output is - roomies!!
but why the output should be concatenation of kammo DJ + roomies!!
also tell what is the value of c?
First, you should malloc the strlen(a) + strlen(b) + 1 because of the '\0' symbol. You already declared char * a = "kammo dj" so you can't allocate memory for that. When you did the malloc for char * a, it returned the location of the memory pool malloc created.
if you just do:
#include<stdio.h>
#include<string.h>
#include<malloc.h>
int main()
{
const char *a="kammo DJ";
const char *b="roomies!!";
char *c;
size_t len = strlen(a) + strlen(b) + 1;
c=(char *)malloc(len*sizeof(char));
strcpy(c,a);
strcat(c,b);
printf("%s\n",c);
// don't forget!
free(c);
return 0;
}
will output 'kammo DJroomies (no space between)
The poblem here is that when you do
a=(char *)malloc(strlen(a) + strlen(b));
It means a is no longer pointing to "kammo DJ". Instead it is pointing to freshly allocated memory contain arbitrary data.
It appears that the first byte of the data a is now pointing to happens to be 0, which effectively makes a the empty string. Which is why you are getting just roomies!! as your result. But that is just luck.
The code you really want is:
#include<stdio.h>
#include<string.h>
main()
{
const char *a="kammo DJ";
const char *b="roomies!!";
char *c;
c=(char *)malloc(strlen(a) + strlen(b) + 1);
strcpy(c,a);
strcat(c,b);
printf("%s\n",c);
}
a=(char *)malloc(strlen(a) + strlen(b));
You need room for the terminating null character. The size of a string is its length + one byte for the null character. Also a was declared to point at the "kammo DJ" string literal. After the malloc call you make the pointer points to something else.
c=strcat(a,b);
a is not a string and contains an indeterminate value after malloc.
I have a string:
str1 = "abcabcabc";
How can I remove the first character? I would like the end result to be:
str1 = "bcabcabc";
If you have a character pointer to a string like:
char *s = "This is my string";
then you can just do s++.
If you have a character array, your best bet may be to have a pointer to that array as well:
char s[] = "This is my string";
char *ps = s;
then you can do ps++ and make sure you use ps rather than s.
If you don't want to have a separate pointer to your array then you can use memmove to copy the data:
memmove (s, s+1, strlen (s+1) + 1); // or just strlen (s)
though none of those will work for an initially empty string so you'll have to check that first. Also keep in mind it's not advisable to attempt modifying string literals in this way (or any way, really) since it's undefined as to whether that's allowed.
Another solution is to simply code up a loop:
for (char *ps = s; *ps != '\0'; ps++)
*ps = *(ps+1);
*ps = '\0';
This will work for all strings, empty or otherwise.
Pointer tricks (zero-cost):
char* s = "abcd";
char* substr = s + 1;
// substr == "bcd"
Or:
char s[] = "abcd";
char* substr = s + 1;
// substr == "bcd"
In-place via memmove:
char s[] = "abcd";
char* substr = s + 1;
memmove(s, substr, strlen(substr) + 1);
// s == "bcd"
Notice that we must use char[] rather than char*, which would refer to read-only memory, as described here. Furthermore, one should not use strcpy in-place because the src and dest must not overlap for strcpy.
Into a new string via strcpy:
char* src = "abcd";
char* substr = src + 1;
char dest[strlen(substr) + 1];
strcpy(dest, substr);
// dest == "bcd"
Into a new string via C++'s std::string::substr:
std::string src = "abcd";
std::string dest = src.substr(1);
// dest == "bcd"
Into a new string via C++'s std::copy:
std::string src = "abcd";
std::string dest;
std::copy(src.begin() + 1, src.end(), std::back_inserter(dest));
// dest == "bcd"
There's a couple dozen other ways (particularly when including C++), but I'll stop here. :)
If you really meant to say
char str1 [] = "abcabcabc";
Then the easiest thing is
str1 = &str1[1];
If you want to modify the actual data, then you have to just move everything up one position. You can use a loop for that or memmove(). A recursive function is overkill.
If you really meant C++ and you're using the string object then you can use
str1 = str1.substr(1);
Here is one way to do it:
int index = 0; //index to cull
memmove( &word[ index ] , &word[ index +1], strlen( word ) - index) ;
Well as far as i know if you are worried about memory allocation you have to copy (str1+1) into a new string that you personally allocate memory for, then free the first pointer.
The really simple way to do it would be to just increment str1 with str1++; That would make it point one character farther than it used to and give you the desired result with just a line of code.
#include <stdio.h>
#include <conio.h>
main(){
char a[10];
int i;
gets(a);
for (i = 0; a[i] != '\0'; i++) {
a[i] = a[i + 1];
}
printf("\n");
puts(a);
getch();
}
#include <stdio.h>
int main() {
char a[15] = "!Hello world!";
sprintf(a,"%s",a+1);
printf("%s",a);
}