my_strcpy gives seg fault - c

#include<stdio.h>
char* my_strcpy(char*,const char*);
int main(){
char a[20];
char* s = "Hello world!";
char* d = a;
my_strcpy(d,s);
printf("\n d : %s \n",d);
return 0;
}
char* my_strcpy(char* dest,const char* sour){
if(NULL == dest || NULL == sour){
return NULL;
}
while(1){
*dest++ = *sour++;
if(*sour == '\0'){
*dest = *sour;
break;
}
}
}
why do we need the char* as a return type for my_strcpy. If the d is " " it gives me a segmentation fault. If I assign it with a it works fine. Why does it give seg fault when given "".
MODIFIED : After the answers
#include<stdio.h>
char* my_strcpy(char*,const char*);
int main(){
char* ret;
char a[20];
char* s = "Hello world!";
char* d = "";
ret = my_strcpy(d,s);
if(NULL == ret){
perror("\nret");
}
// printf("\n d : %s \n",d);
return 0;
}
char* my_strcpy(char* dest,const char* sour){
char* temp;
if(NULL == dest || NULL == sour){
return NULL;
}
temp = dest;
while(1){
*temp++ = *sour++;
if(*sour == '\0'){
*temp = *sour;
break;
}
}
return temp;
}
This still gives a segfault. How to handle the condition if s="" when passed to the function strcpy.

You asked: "If the d is " " it gives me a segmentation fault."
Answer:
If you assign "" or " " to d, there will not be enough space to fit "Hello World". Moreover, a constant string if assigned to a memory page tagged as data might not allow modification.
You asked "why do we need the char* as a return type for my_strcpy" as the original strcpy I presume.
Answer:
You do not have to. You could have void as return type. However, it makes it practical if one is to do something like this:
printf ("%s", strcpy (dest, sour));
Corrected code:
while(1){
*dest++ = *sour++;
if(*(sour-1) == '\0'){
break;
}
or better:
while(*sour != '\0'){
*dest++ = *sour++;
}
*dest = *sour;

Here you:
Assign the value at *sour to *dest
Increment both sour and dest so now the point to the next characters
Test if *dest is now NUL to exit the loop
As you can see, the 3rd step reads from uninitialized memory. You should test if the value that was assigned before incrementing was NUL.
*dest++ = *sour++;
if(*dest == '\0'){
break;
}
If the dest you pass in is a constant string like " " you get a segfault because string constants are stored in read-only memory. They cannot be modified.

Correct:
if(*dest == '\0'){
should be:
if(*(dest - 1) == '\0'){
Note:
*dest++ = *sour++;
is equivalent to
*dest = *sour;
sour++;
dest++;
You increments dest after assignment, and so you are checking \0 at position where garbage value present as you don't initialize a[] -causes Undefined behaviour. Additionally you don't return after while loop.
You can simply write your function as:
char* my_strcpy(char* dest,const char* sour){
if(NULL == dest || NULL == sour)
return NULL;
char* d = dest;
while(*dest++ = *sour++)
;
return d;
}
Give it a try!!

here is a simple version:
char *my_strcpy(char *d, const char *s){
int i=0;
while(d[i++]=*s++)
/*done inside condition*/;
return d;
}

I would advise to implement strcpy as:
char* my_strcpy (char* s1, const char* s2)
{
char* return_val = s1;
*s1 = *s2;
while(*s2 != '\0')
{
s1++;
s2++;
*s1 = *s2;
}
return return_val;
}
Always avoid multiple ++ statements in the same expression. There is never a reason to do so and it will sooner or later give you a handful of undefined/unspecified behavior bugs.

Related

Which string is the longest

My code:
What I'm trying to do is to input two strings, then return the longest one. If they're the same length then return NULL. Now, the code is just outputting gibberish and I cannot find out why. The function returns a pointer to the first character of the largest string. Then it goes through the while loop, and I'm trying to dereference the pointer and print out its value.
Note: I'm revising for an exam and we have to use only pointers and not treat strings as arrays.
#include<stdio.h>
char* string_ln(char*, char*);
int main() {
char str1[20];
char str2[20];
char* length;
scanf("%s%s", str1, str2);
length = string_ln(str1, str2);
while (length != '\0') {
printf("%c", *length);
length++;
}
}
char* string_ln(char*p1, char*p2) {
int count1 = 0;
while (*p1 != '\0') {
count1++;
p1++;
}
int count2 = 0;
while (*p2 != '\0') {
count2++;
p2++;
}
if (count1 > count2) {
return p1;
}
else if (count2 > count1) {
return p2;
}
else {
return NULL;
}
}
In writing string_ln you iterate over both strings completely to find their lengths, and then compare those numbers. This can work, but you don't actually need to do this. You only need to know which is longer. It doesn't matter how much longer the longer string is.
char *string_ln(char *str1, char *str2) {
char *iter1, *iter2;
for (iter1 = str1, iter2 = str2;
*iter1 && *iter2;
iter1++, iter2++);
if (!(*iter1 || *iter2)) {
return NULL;
}
else if (*iter1) {
return str1;
}
else {
return str2;
}
}
We simply need to iterate over both strings, until at least one hits a NULL character. Once we get to that point, we can test to see which iterator is NULL. If it's both of them, then they're the same length. If the first iterator is not NULL, then the first string is longer. Otherwise, the second string is longer.
The benefit to this approach is that we avoid unnecessary work, and make it much quicker to compare strings of very different lengths.
There are a few problems here. First, you're modifying p1 and p2 in the function, so you won't actually return a pointer to the beginning of the largest string, but to its end. One way to avoid this is to iterate over copies of p1 and p2:
char* string_ln(char*p1, char*p2)
{
char* tmp1 = p1;
int count1 = 0;
while (*tmp1 != '\0') {
count1++;
tmp1++;
}
char* tmp2 = p2;
int count2 = 0;
while (*tmp2 != '\0') {
count2++;
tmp2++;
}
if(count1>count2){
return p1;
}
else if(count2>count1){
return p2;
}
else{
return NULL;
}
}
Second, in your main, you're using the %c format string, which works for a single char, not a whole string. Since you have a string anyway, you can avoid a format string and just print it directly. Also, note that you should explicitly check for NULLs:
int main() {
char str1[20];
char str2[20];
char* longest;
scanf("%s%s", str1, str2);
longest = string_ln(str1, str2);
if (longest) {
printf(longest);
} else {
printf("They are the same length");
}
}
I think you're missing to dereference the pointer. Instead of
while(length!='\0')
you'd need
while(*length!='\0')
That said, in the called function, you're reuring pointers after the increment, i.e., the returned pointers do not point to the start of the string anymore. You need to ensure that you return pointers which points to the beginning of the string. You can change your code to
int count1 = 0;
while (p1[count1] != '\0') {
count1++;
}
int count2 = 0;
while (p2[count2] != '\0') {
count2++;
}
so that p1 and p2 does not change.
For starters the function should be declared like
char * string_ln( const char *, const char * );
because the passed strings are not being changed within the function.
You are returning from the function the already modified pointer p1 or p2 that is being changed in one of the while loops
while (*p1 != '\0') {
count1++;
p1++;
}
while (*p2 != '\0') {
count2++;
p2++;
}
So the returned pointer points to the terminating zero '\0' of a string.
Moreover in main before this while loop
length = string_ln(str1, str2);
while(length!='\0'){
printf("%c", *length);
length++;
}
you are not checking whether the pointer length is equal to NULL. As a result the program can invoke undefined behavior.
The function itself can be defined the following way using only pointers.
char * string_ln( const char *p1, const char *p2 )
{
const char *s1 = p1;
const char *s2 = p2;
while ( *s1 != '\0' && *s2 != '\0' )
{
++s1;
++s2;
}
if ( *s1 == *s2 )
{
return NULL;
}
else if ( *s1 == '\0' )
{
return ( char * )p2;
}
else
{
return ( char * )p1;
}
}
and in main you need to write
char *length = string_ln( str1, str2 );
if ( length != NULL )
{
while ( *length )
printf( "%c", *length++ );
}
Pay attention to that the return type of the function is char * instead of const char *. It is because in C there is no function overloading and the returned pointer can point to a constant string or to a non-constant string. It is a general convention in C for declaring string functions.

Keep getting segmentation fault (core dumped)

I keep getting segmentation fault when i try and compile this. Do i need a check possibly for even and odd? I know it means im trying to get memory that i dont have but im not sure where im making the mistake. This is C also.
#include<stdio.h>
int main()
{
char str[41], even[21], odd[21], *p, *pstr, *e, *o;
printf("Enter a string (40 characters maximum):");
scanf("%s", str);
*p=str[0];
*pstr=str[0];
for(*p=even[0]; *p != '\0';p++){
if((p-pstr) % 2 == 0){
*e=*p;
e++;
} else{
*o=*p;
o++;
}
}
*o = '\0';
*e = '\0';
printf("The even string is:%s", even);
printf("The odd string is:%s", odd);
return 0;
}
There is some confusion regarding the initialization of pointers in your code:
*p = str[0] copies the first character from str to the address pointed to by p, which is uninitialized, hence causes undefined behavior.
you should instead initialize the value of p to the address of str[0]:
p = &str[0];
which can be simplified as
p = str;
Here is a corrected version:
#include <stdio.h>
int main(void) {
char str[41], even[21], odd[21], *p, *pstr, *e, *o;
printf("Enter a string (40 characters maximum):");
if (scanf("%40s", str) == 1) {
e = even;
o = odd;
for (p = pstr = str; *p != '\0'; p++) {
if ((p - pstr) % 2 == 0) {
*e = *p;
e++;
} else {
*o = *p;
o++;
}
}
*o = '\0';
*e = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
}
return 0;
}
p has no allocated memory, you can set p = str but not copy the char in str[0] to a random memory address, since p never allocated some memory where it points to.

Copying Character Pointer into another Character Pointer in C Without strcpy

I'm having some issues copying the contents of one pointer to another. I'm not able to get the contents of * s to copy into * a. If I remove the bump for * a, it copies only the last character from s. Also the use of any string library functions or any array notation isn't allowed. Sorry if the formatting is poor, this is my first post. Thanks in advance for any help.
char* copy( char *s )
{
char *a = (char *) malloc(sizeof(char)*length(s));
if (s == NULL)
{
printf("ERROR: OUT OF MEMORY\n" );
return 0;
}
while( *s != '\0' )
{
*a = *s;
s++;
a++;
}
*a = '\0';
return a;
}
Never modify the value of a pointer you have allocated. If you do that, may lose track of the address and be unable to free it.
char* copy( const char *s )
{
char *a = malloc(length(s)+1);
if (a == NULL)
{
perror( "malloc failed" );
return NULL;
}
char *c = a;
while( *s != '\0' )
{
*c = *s;
s++;
c++;
}
*c = '\0';
return a;
}
Very simple test:
int main(int argc, char *argv[])
{
const char *s = "this is a test string";
char *a;
if (NULL != (a = copy(s))) {
printf("The copy is: %s\n", a);
free(a);
}
}
Results in:
The copy is: this is a test string

concatinate two String Using pointer in C

I'm trying to concatenate two strings using pointer in C, but it doesn't work 100%. At the end of the output String, many unknown characters appear...
char* concat_string (char* s1, char* s2) {
char *s;
int k=0;
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
while (*s1!='\0') {
*(s+k)=*s1;
k++;
s1++;
}
while (*s2!='\0') {
*(s+k)=*s2;
k++;
s2++;
}
return s;
}
int main () {
char *ch1, *ch2, *s;
char cch1[10], cch2[10];
printf("ch1 ? ");
scanf("%s",cch1);
printf("ch2 ? ");
scanf("%s",cch2);
ch1=cch1;
ch2=cch2;
s=concat_string(ch1, ch2);
printf("\n%s + %s = ", ch1, ch2);
while (*s!='\0') {
printf("%c", *s);
s++;
}
}
You're not including space for the terminator in the concatenated result. This:
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
should be:
s = malloc(strlen(s1) + strlen(s2) + 1);
You're not copying the terminator either, which explains the result you're seeing.
Also, don't cast malloc()'s return value in C, and make your input strings const.
Your code is very hard to read. The use of an integer indexing variable instead of just using pointers makes it needlessly complicated. For reference, here's how I would write it:
char * concat_string(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) + 1);
if(s != NULL)
{
char *p = s;
while((*p++ = *s1++) != '\0');
--p;
while((*p++ = *s2++) != '\0');
}
return s;
}
This is of course still somewhat terse, but I'd argue it's more readable than your version.
printf expects null terminated strings. Otherwise, it will print whatever characters in memory until it hits one. Your concat_string function doesn't put a null terminator on the string.
char* concat_string (char* s1, char* s2){char *s;int k=0;
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
while(*s1!='\0'){*(s+k)=*s1;k++;s1++; }
while(*s2!='\0'){*(s+k)=*s2;k++;s2++;}
*(s+k) = 0;
return s;
}
Also, this function is already written for you, just try using strcat.

Strange behavior of String tokenizer in C

I have written the following program to resolve a path to several directory names
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *
tokenizer(char *path, char **name){
char s[300];
char *buffer;
memcpy(s, path, strlen(path)+1);
printf("%s\n",s); // PROBLEM
int i=0;
while(s[i] == '/'){
i++;
}
if (i == strlen(path)){
return NULL;
}
*name = strtok_r(s, "/", &buffer);
return buffer;
}
int main(void){
char str[300];
char *token, *p;
scanf("%s",str);
p = tokenizer(str, &token);
if (p != NULL)
printf("%s\n",token);
else
printf("Nothing left\n");
while((p=tokenizer(p, &token)) != NULL){
printf("%s\n",token);
}
}
Output of the above program
Input: a/b/c
Output: a/b/c
a/b/c
a
b/c
b
c
c
If I comment the line labelled PROBLEM
Input: a/b/c
Output: Some garbage value
Can somebody explain me the reason for this strange behavior?
Note:
I have realised that s is a stack allocated variable and it ceases to exist in function main() but why does the program works when I use printf() ?
In addition to what geekasaur says:
strtok_r's 3rd parameter is used incorrectly, in two ways:
1. It should be initialized to NULL before the first call.
2. It shouldn't be used in any way (you return it to the caller). It should only be passed to another strtok_r call.
You are returning a pointer into a stack-allocated string (buffer points into s); s's memory ceases to be meaningful after tokenize returns.
You cannot do this
char s[300];
char *buffer;
...
*name = strtok_r(s, "/", &buffer);
return buffer;
Here buffer is a pointer to a s[300] position. s[300] is a function local variable allocated on the stack when the function is called and destroyed when the function returns.
So you are not returning a valid pointer, you cannot use that pointer out of the function.
Along with the observations that you're returning a pointer to a local variable, I think it's worth noting that your tokenizer is almost 100% pointless.
Most of what your tokenizer does is skip across any leading / characters before calling strtok_r -- but you're passing '/' as the delimiter character to strtok_r, which will automatically skip across any leading delimiter characters on it own.
Rather simpler code suffices to print out the components of a path without the delimiters:
char path[] = "a/b/c";
char *pos = NULL;
char *component = strtok_r(path, "/", &pos);
while (NULL != component) {
printf("%s\n", component);
component = strtok_r(NULL, "/", &pos);
}
Try this:
char*
token(char * path, char ** name){
static char * obuffer = NULL;
char * buffer = NULL, * p, * q;
if(path == NULL) {
buffer = realloc(buffer, strlen(obuffer) + 1);
p = obuffer;
} else {
buffer = malloc(257);
p = path;
}
if(!buffer) return NULL;
q = buffer;
if(!p || !*p) return NULL;
while(*p != '\0') {
if(*p == '/') {
p++; /* remove the / from string. */
break;
}
*q ++ = *p++;
}
*q ++ = '\0';
obuffer = p;
*name = buffer;
return buffer;
}
int main(void)
{
char * s = "foo/baa/hehehe/";
char * name = NULL;
char * t = token(s, &name);
while(t) {
printf("%s\n", name);
t = token(NULL, &name);
}
return 0;
}
the output:
foo
baa
hehehe
But you are basically "reinventing the wheel" of strtok() function..

Resources