I have an exercise in class where I have to copy the strstr() function in C (from <string.h> library). Here is my code
char *ft_strcpy(char *dest, char *src)
{
int i;
i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (dest);
}
This code is fully functional but when I try with a dest string that is smaller than the src string, it shows an unpredictable result that ends up overwriting src too. The original strstr() function's answer to that is to abort program in that situation. How can I make my program abort given that I can't use the abort() function?
You must check your string.
May be one of them is NULL.
When you do : While (str[i] ..)
You don't know if (str) is NULL or not.
Do :
While (str && str[i] != '\0')
It's better.
You can also check if dest is malloc fine because if you don't have any memory for your string dest you can't assign value.
I would suggest a compact implementation
char * ft_strcpy(char * dest, const char * src) {
if (strlen(dest) < strlen(src)) { /* abort(); or exit(1); */ }
char * s = dest;
while (*dest++ = *src++);
return s;
}
The actual bounds checking is implemented in the safer version of strcpy, i.e. strcpy_s. You can find an implementation in Safe C Library.
Related
This code finds the next word in the string.
For example
given an input of " my cake" the function should return "my cake". as the expected output
If I use return then the output is (null), but I use printf then the code works
I would like to know how to get the expected output using return.
#include <stdio.h>
int main()
{
char* str[1000];
printf("enter:");
fgets(str,1000,stdin);
printf("%s",find_word_start(str));
}
char* find_word_start(char* str){
char* result[1000];
int c = 0, d = 0;
while(str[c] ==' ') {
c++;
}
while(str[c] != '\0'){
result[d++] = str[c++];
if(str[c]==' ') {
result[d++] = str[c++];
}
while(str[c]==' ') { //
c++;
}
}
result[d] = '\0';
//print or return char?
return result;
}
char* result[1000]; creates an array of 1000 pointers. That's wrong in a number of ways.
You want a block of 1000 chars, not pointers.
Actually, 1000 is not the number of characters you want. You usually want a smaller number, but you could also want a larger number.
You don't want to store the result in automatically allocated memory, because that will be freed as soon as you exit the function. Use malloc (or something that does a malloc such as strdup).
Fix:
// Returns a copy that needs to be freed.
char* find_word_start(const char* src) {
while (*src == ' ')
++src;
size_t len = 0;
while (str[len] != '\0')
++len;
++len; // Include NUL
result = malloc(len);
char* dst = result;
while (len--)
*(dst++) = *(src++);
return result;
}
Well, I was avoiding using string functions above like you did, but they greatly simplify the solution.
// Returns a copy that needs to be freed.
char* find_word_start(const char* src) {
while (*src == ' ')
++src;
return strdup(src);
}
That said, since you return the tail end of the string, you could simply return a pointer into the existing string.
// Returns a pointer into the provided string.
const char* find_word_start(const char* str) {
while (*str == ' ')
++str;
return str;
}
The following line allocates memory space in the stack but after the function ends everything is gone:
char result[1000];
You need to allocate memory in the heap like that:
char *result = malloc(sizeof(char) *1000);
Note: don't forget to free that memory space by free function.
char *strcat(char*dest, char*src) {
while (dest != '\0') {
*dest++;
}
while (src != '\0') {
*dest++ = *src++;
}
return dest;
}
I keep getting a segmentation fault on the line *dest++ = *src++. Any ideas on how to fix the problem?
Your code has 4 problems:
you are comparing pointers to the null character instead of comparing the character they point to. Since it will take incrementing the pointer an awful lot of times before it becomes 0, if at all, you are reading and/or writing beyond the end of the buffers, from/to invalid memory before this happens, hence the crash.
you do not null terminate the destination string.
you return the pointer to the end of the destination string instead of the original destination string. This might be a useful API, but you should use a different name for that.
the src pointer should be declared as const char * to conform to the standard declaration for this function and to allow passing pointers to constant strings as sources.
Here is a corrected version:
char *strcat(char *dest, const char *src) {
char *saved = dest;
while (*dest != '\0') {
dest++;
}
while ((*dest++ = *src++) != '\0') {
continue;
}
return saved;
}
Okay: the Kernighan way:
char *strcat(char *dest, char *src)
{
char *org = dest;
while(*dest++){;}
// at this moment, *dest MUST be pointing to '\0'
while(*dest++ = *src++){;}
// at this moment, *dest MUST be pointing to '\0' agian
return org;
}
Update (courtously #chqrlie):
char *strcat(char *dest, char *src)
{
char *org = dest;
for(; *dest; dest++) {;}
// at this moment, dest MUST be pointing to '\0'
while(*dest++ = *src++) {;}
// at this moment, dest points past the '\0', but who cares?
return org;
}
dest and source will never become '\0' if they aren't null to begin with (or maybe after a long time to be correct, but you'll probalby run out of memory long before that).
You should use:
while(*dest != '\0'){
dest++;
}
while(*src != '\0'){
*dest++ = *src++;
}
to check the values underneath the pointers.
There are some other problems too:
the resulting string is not null-terminated.
a pointer to the end of the string is returned.
As mentioned by others: src should be a const pointer too.
This should do it:
char *strcat(char *dest, const char *src)
{
char *start_pos = dest;
while(*dest != '\0')
dest++;
while(*src != '\0')
*dest++ = *src++;
*dest = '\0';
return start_pos;
}
Minor detail: I would give this funtion some other name than the standard used strcat().
This is the strcat function that I have implemented, but I get a segmentation fault when I go to the line *dst++ = *src++;. I have incremented src till '\0' as I want to append the next string starting from there. Can you please tell me why it gives segmentation fault? Am I doing any logical mistake by doing *dst++ = *src++;?
char *strconcat(char *dst, char *src)
{
char *fdst;
fdst = dst;
if (dst == '\0' || src == '\0')
return fdst;
while (*dst != '\0')
dst++;
while (*src != '\0')
*dst++ = *src++;
return fdst;
}
Hey i went through many solution given below and i made following changes but still i get segmentation problem when i start concatenate two strings, here is my entire code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *strconcat(char *dst, const char *src);
void main()
{
char *str1 = "Stack";
char *str2 = "overflow";
printf("MY CONCAT:%s\n",strconcat(str1, str2));
printf("INBUILT CONCAT:%s\n",strcat(str1, str2));
}
char *strconcat(char *dst, const char *src)
{
char *fdst;
int dst_len = 0, src_len = 0;
dst_len = strlen(dst);
src_len = strlen(src);
fdst = (char *) malloc(dst_len + src_len + 1);
fdst = dst;
if (src == NULL)
return fdst;
while(*dst)
{
dst++;
fdst++;
}
while(*src)
*fdst++ = *src++;
*fdst = '\0';
return fdst;
}
The idiomatic way is
while (*dst++ = *src++);
Some observations:
You're not copying the termination, leaving a non-terminated string in dst. This is the cause of the actual problems.
This: if(dst == '\0'||src == '\0') is weird, if the intent was comparing against NULL you should do so more directly and not use character literals.
The src argument should be const char * since it's read-only. Using const for pointers that are "input" arguments is a very good idea, since it communicates intent right there in the prototype. It also helps avoid mistakingly writing to the wrong string.
You can't have a function beginning with str, that "namespace" is reserved for the standard library.
Multiple problems here:
PROBLEM - I
The memory allocated with malloc
fdst = (char *) malloc(dst_len + src_len + 1);
is lost as some lines later you are doing this:
fdst = dst;
replacing the address returned by malloc in 'fdst' with the address of the target string..!! Hope you fix it on your own, its darn simple.
PROBLEM - II
After fixing that above problem, you'll have to fix this:
while(*dst)
{
dst++;
fdst++;
}
don't only increment, you'll also have to copy your characters from dst to fdst as this will be your concatenated string.
PROBLEM - III
finally, you are doing this in the end..!!
return fdst;
you realize the mistake there right? Hope you can take care of that [ Hint: save the starting address and return it in the end, not the incremented pointer ;) ]
Note: Not an optimised solution but, fixes your code.
Possible crash causes:
1) may be the length of your dst is not enougth to support concatunation of src and dst.
2) may be you have called your function with input char pointers which they are not pointed to allocated memory (staic or dynamic)
3) may be your input dst char pointer is pointing to a constant string.
another remark you have to finish your dst string with '\0' after the second while
while (*src != '\0')
*dst++ = *src++;
*dst='\0';
Try this:
while(*original)
original++;
while(*add)
{
*original = *add;
add++;
original++;
}
*original = '\0';
It may be helpful.
There are pretty much errors in your code:
if (dst == '\0' || src == '\0') what you are trying by checking this. First of all this is not clear condition - you should use if (dst == NULL || src == NULL) or if (*dst == '\0' || *src == '\0') to be more accurate and make this more clear. Second even if this condition would be right (if (*dst == '\0' || *src == '\0')) you are not achieving what concatenation should. At least if *src == '\0' you should probably return original string - dst.
You should probably check if dst is long enough to store your new string or you should allocate new buffer inside function big enough to hold both dst and src (malloc (strlen(dst) + strlen(src) + 1) - note extra +1 for holding terminating '/0' character)
You are not terminating your result string.
And the answer for your questions: segmentation fault is probably because your dst is NOT long enough to hold both src and dst. You can use hint in point 2. to modify your code or you can declare bigger buffer outside function that will have size at least (strlen(dst) + strlen(src) + 1.
Another reason could be calling this function with constant string e.g char *str = "string";. In this case most probably string is constant and you are not allowed to modify it (in most operating system this will be located in non-modifiable part of program and you will have only pointer to this location).
Your code is correct , see below for explanation !
I think you are using char * for the src and dst string in the caller.
Using an array declaration there will help, since your program is crashing at
*dst++ = *src++;
because dst and src point to strings which are constants and cannot be modified.
In the following code I have just added main, and your function is unchanged !
#include<stdio.h>
char *strconcat(char *dst, char *src)
{
char *fdst;
fdst = dst;
if (dst == '\0' || src == '\0')
return fdst;
while (*dst != '\0')
dst++;
while (*src != '\0')
*dst++ = *src++;
return fdst;
}
void main()
{
char dest[10] = "one" ;
char src[10] = "two" ;
printf("\n%s " , strconcat( dest , src ) ) ;
}
Although you need to change the if statement to
if (*dst == '\0' || *src == '\0')
return fdst;
is this the standard code for strstr i made????
char* fstrset(char *s,char *t)
{
int b, i=0,j=0;
while(*(s+i)!='\0')
{
if(*(t+j)=='\0')
break;
else if(*(s+i)==*(t+j))
{
i++;j++;b=1;
}
else
{ i++;b=0;j=0;
}
}
if(b==0)
return((char*)NULL);
else if(b==1)
return(s+i-j);
}
This is all the standard has to say about it:
7.21.5.7 The strstr function
Synopsis
#include <string.h>
char *strstr(const char *s1, const char *s2);
Description
The strstr function locates the first
occurrence in the string pointed to by
s1 of the sequence of characters
(excluding the terminating null
character) in the string pointed to by
s2.
Returns
The strstr function
returns a pointer to the located
string, or a null pointer if the
string is not found. If s2 points to a
string with zero length, the function
returns s1.
So, it looks like you're missing const qualifiers on arguments.
As for style, note that *(ptr+index) can be replaced by ptr[index], and size_t is the best type to use for indexing a pointer.
As for being a common way to implement it, compare with GCC's code:
char *
strstr (const char *s1, const char *s2)
{
const char *p = s1;
const size_t len = strlen (s2);
for (; (p = strchr (p, *s2)) != 0; p++)
{
if (strncmp (p, s2, len) == 0)
return (char *)p;
}
return (0);
}
Your code is buggy. Given:
char *haystack = "fififi-trixabelle";
char *needle = "fifi-trixabelle";
fstrset(haystack, needle) returns incorrectly returns NULL.
Besides the bug mentioned by caf there are others:
1) Uninitialized b. If s points to '\0', closing brace may be reached, omitting any return statements.
2) If characters match up to the end of string pointed to by s there is no check if the string pointed to by t ends too.
What does this do? It looks like gibberish. Why adding pointers, and mixing them with ints? Sorry, but the whole thing doesn't make sense.
And to answer your question, i don't think so. But if you compile it and it runs, then yes.
Okay, your code does make sense when you look at it closer. Yes, it does look like it will compile, if thats what you mean by standard code.
inline char* strstr(char* __s1, const char* __s2)
{
return __builtin_strstr(const_cast<const char*>(__s1), __s2);
}
a quick read through seems to show that the code works (there are probably edge cases that dont work). You tell us, does it work?
But why do it? just call strstr
There is no 'standard code', just the standard result.
It is unlikely that any implementation in a standard C library uses array indexing, so it is unlikely that your code matches any implementation in line-by-line detail.
char* fstrstr(char *s1,char *s2)
{
int i=0,flag=0;
char *s4,*s3;
// s4 for retaining the value of s2
s4 = s2;
while(*s1 != '\0' && *s2 != '\0')
{
if(*s1 == *s2)
{
*(s3+i) = *s1;
s2++;
s1++;
i++;
flag = 1;
}
else
{
i = 0;
s1++;
// Initialize s2 again from its address
s2 = s4;
flag = 0;
}
}
if(flag == 1)
{
while(*s1 != '\0')
{
*(s3+i) = *s1;
i++;
s1++;
}
*(s3+i) = '\0';
}
if(flag == 1)
return (s3);
if(flag==0)
{
*s3 = NULL;
return (s3);
}
}
There is no "standard code", only standard results.
It is unlikely that any implementation in the standard C library will use array indexes, so your code is unlikely to match any implementation in the line implementation.
char *strstr(const char *s1, const char *s2) {
char *a = s1, *b = s2;
for (;;)
if (!*b) return (char *)s1;
else if (!*a) return NULL;
else if (*a++ != *b++) {a = ++s1; b = s2;}
}
I'm looking to remove all punctuation from a string and make all uppercase letters lower case in C, any suggestions?
Just a sketch of an algorithm using functions provided by ctype.h:
#include <ctype.h>
void remove_punct_and_make_lower_case(char *p)
{
char *src = p, *dst = p;
while (*src)
{
if (ispunct((unsigned char)*src))
{
/* Skip this character */
src++;
}
else if (isupper((unsigned char)*src))
{
/* Make it lowercase */
*dst++ = tolower((unsigned char)*src);
src++;
}
else if (src == dst)
{
/* Increment both pointers without copying */
src++;
dst++;
}
else
{
/* Copy character */
*dst++ = *src++;
}
}
*dst = 0;
}
Standard caveats apply: Completely untested; refinements and optimizations left as exercise to the reader.
Loop over the characters of the string. Whenever you meet a punctuation (ispunct), don't copy it to the output string. Whenever you meet an "alpha char" (isalpha), use tolower to convert it to lowercase.
All the mentioned functions are defined in <ctype.h>
You can either do it in-place (by keeping separate write pointers and read pointers to the string), or create a new string from it. But this entirely depends on your application.
The idiomatic way to do this in C is to have two pointers, a source and a destination, and to process each character individually: e.g.
#include <ctype.h>
void reformat_string(char *src, char *dst) {
for (; *src; ++src)
if (!ispunct((unsigned char) *src))
*dst++ = tolower((unsigned char) *src);
*dst = 0;
}
src and dst can be the same string since the destination will never be larger than the source.
Although it's tempting, avoid calling tolower(*src++) since tolower may be implemented as a macro.
Avoid solutions that search for characters to replace (using strchr or similar), they will turn a linear algorithm into a geometric one.
Here's a rough cut of an answer for you:
void strip_punct(char * str) {
int i = 0;
int p = 0;
int len = strlen(str);
for (i = 0; i < len; i++) {
if (! ispunct(str[i]) {
str[p] = tolower(str[i]);
p++;
}
}
}