I've tried reinventing the strcpy C function, but when I try to run it I get this error:
Unhandled exception at 0x00411506 in brainf%ck.exe: 0xC0000005: Access violation writing location 0x00415760.
The error occurs in the *dest = *src; line. Here's the code:
char* strcpy(char* dest, const char* src) {
char* dest2 = dest;
while (*src) {
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return dest2;
}
EDIT: Wow, that was fast. Here's the calling code (strcpy is defined in mystring.c):
#include "mystring.h"
#include <stdio.h>
int main() {
char* s = "hello";
char* t = "abc";
printf("%s", strcpy(s, t));
getchar();
return 0;
}
char* s = "hello";
char* t = "abc";
printf("%s", strcpy(s, t));
The compiler placed your destination buffer, s, in read-only memory since it is a constant.
char s[5];
char* t = "abc";
printf("%s", strcpy(s, t));
Should fix this problem. This allocates the destination array on the stack, which is writable.
The obvious potential problem is that your output buffer doesn't have enough memory allocated, or you've passed in NULL for dest. (Probably not for src or it would have failed on the line before.)
Please give a short but complete program to reproduce the problem, and we can check...
Here's an example which goes bang for me on Windows:
#include <stdlib.h>
char* strcpy(char* dest, const char* src) {
char* dest2 = dest;
while (*src) {
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return dest2;
}
void main() {
char *d = malloc(3);
strcpy(d, "hello there this is a longish string");
}
Note that in this case I had to exceed the actual allocated memory by a fair amount before I could provoke the program to die - just "hello" didn't crash, although it certainly could depending on various aspects of the compiler and execution environment.
Your strcpy() is fine. You are writing to read-only memory. See this description here.
If you had written this, you'd be fine:
#include "mystring.h"
#include <stdio.h>
int main() {
char s[] = "hello";
char t[] = "abc";
printf("%s", strcpy(s, t));
getchar();
return 0;
}
There is a problem with calling of your reinvented strcpy routine in the main routine, both character array:
char* s = "hello";
char* t = "abc";
will land into memory READ ONLY segment at compile time. As you're trying to write to memory pointed by s in the routine strcpy, and since it points to a location in a READ ONLY segment, it will be caught, and you'll get an exception. These strings are READ ONLY!
Make sure dest has it's memory allocated before calling that function.
Probably an issue with the caller: did you check the dest pointer? Does it point to something valid or just garbage? Besides that, the least you could do is check for null pointers, like if (!dest || !source) { /* do something, like return NULL or throw an exception */ } on function entry. The code looks OK. Not very safe, but OK.
There are several errors.
You don't allocate a return buffer that can hold the copied string.
You don't check to see if src is null before using *src
You are both tring to get the answer in a parameter and return the value. Do one or the other.
You can easily overrun the dest buffer.
Good luck.
when ever the code starting execution(generaly it starts from main function). here the code means sequence of execution.so, when the process(sequence of execution) starts , the PCB(process control block) is created,the pcb having complete infromation about the process like process address space,kernal stack,ofdt table like this.
in your code
char* s = "hello";
char* t = "abc";
this is the what you have taken inputs of two strings like this.
here, the the strings(which means double quoted) which are present in text section of the process address space . here text section is the one of the section which is present in the process address space and text section only having the permissions of read-only. that is why when you trying to modify the source string/destination string, we MUST NOT allowable to change the whatever data is present in the text setion. so, this is what the reason for your code you need to be CAUTIOUS. hope you understand.
Related
Like a question below, i have to use the pointer concept to copy array from one to another in mystrcpy2 function, unlike mystrcpy function that does not use the pointer concept. Anyway, I typed my answer, " dest = src;" which seemed to be overly simple but right answer for me. But when I type in the input, like "Hello World", it shows like "Hello World ???" like strange letters in the back. But when I type short words like "abc", the result is exactly "abc."
Is it simply a matter of computer or did I do something wrong?
I"m also wondering if "while (*src) *dest++=*src++;" works as well?
/*Complete the mystrcpy2() function that copies the null-terminated string pointed by src to the string pointed by dest.
The mystrcpy2() should give the same result with the mystrcpy() that uses an index based array traversal approach.
Note that adding local variables are not allowed in implementing the mystrcpy2().
Write and submit the source code of your "mystrcpy2()" function.
*/
#include <stdio.h>
void mystrcpy(char dest[], char src[])
{
int i=0,j=0;
while (src[i])
dest[j++] = src[i++];
}
void mystrcpy2(char *dest, char *src)
{
dest = src;
}
int main(void)
{
char mystr1[256];
char mystr2[256];
gets(mystr1);
mystrcpy(mystr2, mystr1);
puts(mystr2);
mystrcpy2(mystr2, mystr1);
puts(mystr2);
return 0;
}
Your implementation of mystrcpy2 does not copy anything. In fact, it does nothing at all. When you execute dest = src, you are copying the memory location pointed to by the src variable, not the data at that location. To actually copy the data, you need to deference the pointer, using '*'. So you would do
*dest = *src;
This copies the data from src to dest. But it only copies one character. You need to increment src and dest and then do this again to copy the next character, and you need to keep doing this until you hit the string terminator i.e. until *src == 0. Here's the full implementation.
void mystrcpy2(char *dest, char *src)
{
while (*src != 0) {
*dest = *src;
dest++;
src++;
}
// don't forget to add a terminator
// to the copied string
*dest = 0;
}
And here's the exact same thing in a shorter version.
void mystrcpy2(char *dest, char *src)
{
while (*(dest++) = *(src++));
}
I'm doing a pointer version of the strcat function, and this is my code:
void strcat(char *s, char *t);
int main(void) {
char *s = "Hello ";
char *t = "world\n";
strcat(s, t);
return 0;
}
void strcat(char *s, char *t) {
while (*s)
s++;
while ((*s++ = *t++))
;
}
This seems straightforward enough, but it gives bus error when running on my Mac OS 10.10.3. I can't see why...
In your code
char *s = "Hello ";
s points to a string literal which resides in read-only memory location. So, the problem is twofold
Trying to alter the content of the string literal invokes undefined behaviour.
(almost ignoring point 1) The destination pointer does not have enough memory to hold the concatinated final result. Memory overrun. Again undefined behaviour.
You should use an array (which resides in read-write memory) with sufficient length to hold the resulting (final) string instead (no memory overrun).
Suggestion: Don't use the same name for user-defined functions as that of the library functions. use some other name, e.g., my_strcat().
Pseudocode:
#define MAXVAL 512
char s[MAXVAL] = "Hello";
char *t = "world\n"; //are you sure you want the \n at the end?
and then
my_strcat(s, t);
you are adding the text of 't' after the last addres s is pointing to
char *s = "Hello ";
char *t = "world\n";
but writing after 's' is undefined behavior because the compiler might put that text in constant memory, in your case it crashes so it actually does.
you should reserve enough memory where s points to by either using malloc or declare it array style
char s[32] = "Hello ";
I have written the following program (it is given as an example in one of the best text books). When I compile it in my Ubuntu machine or at http://www.compileonline.com/compile_c_online.php, I get "segmentation fault"
The problem is with while( *p++ = *str2++)
I feel it is a perfectly legal program. Experts, please explain about this error.
PS: I searched the forum, but I found no convincing answer. Some people even answered wrong, stating that *(unary) has higher precedence than ++ (postfix).
#include <stdio.h>
#include <string.h>
int main()
{
char *str1= "Overflow";
char *str2= "Stack";
char *p = str1;
while(*p)
++p;
while( *p++ = *str2++)
;
printf("%s",str1);
return 0;
}
Thanks
str1 and str2 point to string literals. You aren't allowed to modify those. Even if you could, there isn't enough memory allocated for the string to hold the characters you're trying to append. Instead, initialize a sufficiently large char array from a string literal:
char str1[14] = "Overflow";
I feel it is a perfectly legal program.
Unfortunately, it is not. You have multiple, severe bugs.
First of all, you are creating pointers to string literals char *str1= "Overflow"; and then you try to modify that memory. String literals are allocated in read-only memory and attempting to write to them results in undefined behavior (anything can happen).
Then you have while(*p) ++p; which looks for the end of the string, to find out where to append the next one. Even if you rewrite the pointers to string literals into arrays, you don't have enough free memory at that location. You must allocate enough memory to hold both "Overflow" and "Stack", together with the string null termination.
You should change your program to something like this (not tested):
#include <stdio.h>
int main()
{
char str1[20] = "Overflow"; // allocate an array with enough memory to hold everything
char str2[] = "Stack"; // allocate just enough to hold the string "Stack".
char *p1 = str1;
char *p2 = str2;
while(*p1)
++p1;
while(*p1++ = *p2++)
;
printf("%s",str1); // should print "OverflowStack"
return 0;
}
Or of course, you could just #include <string.h> and then strcat(str1, str2).
Because you are crossing the string boundary of Overflow (str1) is why you are getting sigsegv.
str1 does not have enough memory allocated to accomodate beyond Overflow.
I have an exercise where I need to write a wrapper function for strcat. After it prints the string length (for debugging) it seg faults and I am not quite sure why. Any help would be greatly appreciated.
EDIT: I didn't specify that the wrapper function is supposed to guarantee that it never goes outside of the bounds of memory allocated for destination. This is why I allocated only enough memory for "string" in destination and reallocating more in the Strcat() wrapper.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* Strcat(char* destination, const char* source);
int main(void)
{
(void)printf("This strcat cannot fail!\n");
char* destination = (char*)malloc(sizeof(char)*7);
destination = "string";
(void)printf("%s\n", destination);
Strcat(destination, " concatination");
(void)printf("%s\n", destination);
(void)printf("It works!\n");
free(destination);
return 0;
}
char* Strcat(char* destination, const char* source)
{
(void)printf("%d\n", (strlen(destination)+strlen(source))*sizeof(char));
if((sizeof((strlen(destination)+strlen(source)))+1) > sizeof(destination))
destination = (char*)realloc(destination, sizeof((strlen(destination)+strlen(source)))+1);
return strcat(destination, source);
}
This line:
destination = "string";
overwrites the pointer returned from malloc(3) so you lose that memory forever. You probably meant to copy that string, so use strcpy(3) or something.
if((sizeof((strlen(destination)+strlen(source)))+1) > sizeof(destination))
That's wrong, sizeof doesn't give you anything comparable to the length of the string. Don't use it here.
Moreover, you can't really get the number of allocated bytes of the string. So if you know destination has been allocated with malloc[*], you should realloc unconditionally:
destination = (char*)realloc(destination, strlen(destination)+strlen(source)+1);
Again, no sizeof. And be prepared to handle allocation failures, which means saving the old value of destination and freeing it when realloc returns 0.
[*] Note that destination = "string" breaks this premise.
Try summat like
char *Strcat(char *d, const char *s) /* please put in the proper names - i am being lazy*
{
int dLen = strlen(d); /* ditto above */
int sLen = strlen(s);
d = (char *)realloc(d, dLen + sLen +1);
return strcat(d, s);
}
I'm trying to learn C programming and spent some time practicing with pointers this morning, by writing a little function to replace the lowercase characters in a string to their uppercase counterparts. This is what I got:
#include <stdio.h>
#include <string.h>
char *to_upper(char *src);
int main(void) {
char *a = "hello world";
printf("String at %p is \"%s\"\n", a, a);
printf("Uppercase becomes \"%s\"\n", to_upper(a));
printf("Uppercase becomes \"%s\"\n", to_upper(a));
return 0;
}
char *to_upper(char *src) {
char *dest;
int i;
for (i=0;i<strlen(src);i++) {
if ( 71 < *(src + i) && 123 > *(src + i)){
*(dest+i) = *(src + i) ^ 32;
} else {
*(dest+i) = *(src + i);
}
}
return dest;
}
This runs fine and prints exactly what it should (including the repetition of the "HELLO WORLD" line), but afterwards ends in a Segmentation fault. What I can't understand is that the function is clearly compiling, executing and returning successfully, and the flow in main continues. So is the Segmentation fault happening at return 0?
dest is uninitialised in your to_upper() function. So, you're overwriting some random part of memory when you do that, and evidently that causes your program to crash as you try to return from main().
If you want to modify the value in place, initialise dest:
char *dest = src;
If you want to make a copy of the value, try:
char *dest = strdup(src);
If you do this, you will need to make sure somebody calls free() on the pointer returned by to_upper() (unless you don't care about memory leaks).
Like everyone else has pointed out, the problem is that dest hasn't been initialized and is pointing to a random location that contains something important. You have several choices of how to deal with this:
Allocate the dest buffer dynamically and return that pointer value, which the caller is responsible for freeing;
Assign dest to point to src and modify the value in place (in which case you'll have to change the declaration of a in main() from char *a = "hello world"; to char a[] = "hello world";, otherwise you'll be trying to modify the contents of a string literal, which is undefined);
Pass the destination buffer as a separate argument.
Option 1 -- allocate the target buffer dynamically:
char *to_upper(char *src)
{
char *dest = malloc(strlen(src) + 1);
...
}
Option 2 -- have dest point to src and modify the string in place:
int main(void)
{
char a[] = "hello world";
...
}
char *to_upper(char *src)
{
char *dest = src;
...
}
Option 3 -- have main() pass the target buffer as an argument:
int main(void)
{
char *a = "hello world";
char *b = malloc(strlen(a) + 1); // or char b[12];
...
printf("Uppercase becomes %s\n", to_upper(a,b));
...
free(b); // omit if b is statically allocated
return 0;
}
char *to_upper(char *src, char *dest)
{
...
return dest;
}
Of the three, I prefer the third option; you're not modifying the input (so it doesn't matter whether a is an array of char or a pointer to a string literal) and you're not splitting memory management responsibilities between functions (i.e., main() is solely responsible for allocating and freeing the destination buffer).
I realize you're trying to familiarize yourself with how pointers work and some other low-level details, but bear in mind that a[i] is easier to read and follow than *(a+i). Also, there are number of functions in the standard library such as islower() and toupper() that don't rely on specific encodings (such as ASCII):
#include <ctype.h>
...
if (islower(src[i])
dest[i] = toupper(src[i]);
As others have said, your problem is not allocating enough space for dest. There is another, more subtle problem with your code.
To convert to uppercase, you are testing a given char to see if it lies between 71 ans 123, and if it does, you xor the value with 32. This assumes ASCII encoding of characters. ASCII is the most widely used encoding, but it is not the only one.
It is better to write code that works for every type of encoding. If we were sure that 'a', 'b', ..., 'z', and 'A', 'B', ..., 'Z', are contiguous, then we could calculate the offset from the lowercase letters to the uppercase ones and use that to change case:
/* WARNING: WRONG CODE */
if (c >= 'a' && c <= 'z') c = c + 'A' - 'a';
But unfortunately, there is no such guarantee given by the C standard. In fact EBCDIC encoding is an example.
So, to convert to uppercase, you can either do it the easy way:
#include <ctype.h>
int d = toupper(c);
or, roll your own:
/* Untested, modifies it in-place */
char *to_upper(char *src)
{
static const char *lower = "abcdefghijklmnopqrstuvwxyz";
static const char *upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static size_t n = strlen(lower);
size_t i;
size_t m = strlen(src);
for (i=0; i < m; ++i) {
char *tmp;
while ((tmp = strchr(lower, src[i])) != NULL) {
src[i] = upper[tmp-lower];
}
}
}
The advantage of toupper() is that it checks the current locale to convert characters to upper case. This may make æ to Æ for example, which is usually the correct thing to do. Note: I use only English and Hindi characters myself, so I could be wrong about my particular example!
As noted by others, your problem is that char *dest is uninitialized. You can modify src's memory in place, as Greg Hewgill suggests, or you can use malloc to reserve some:
char *dest = (char *)malloc(strlen(src) + 1);
Note that the use of strdup suggested by Greg performs this call to malloc under the covers. The '+ 1' is to reserve space for the null terminator, '\0', which you should also be copying from src to dest. (Your current example only goes up to strlen, which does not include the null terminator.) Can I suggest that you add a line like this after your loop?
*(dest + i) = 0;
This will correctly terminate the string. Note that this only applies if you choose to go the malloc route. Modifying the memory in place or using strdup will take care of this problem for you. I'm just pointing it out because you mentioned you were trying to learn.
Hope this helps.