2
\$\begingroup\$

Created a new typedef and functions supporting it, making it user-friendly [specifically programmer-friendly].

What does the code do?

  • It makes users [programmers] easy to deal with strings as most functions are there.
  • Additionally, we can append, obtain substrings, replace string very very easily
  • Also there is no specific limit to the string itself but most functions limit the str to GLOBAL_MAX_CHAR_LIMIT which is defined in mystring.h

Note: This code may contain bugs but I have fixed tons of them which I encountered. Also sstrreplace() is limited to have 7 chars in replacing strings -> I dont know why but if the length is greater than 7 wierd things happen <- I am in progress of finding its solution.

Also got to know that gets() is not safe so I used fgets() and removed '\n' in strinput()! All suggestions, feedbacks and bug-encounters are welcome!

Note: This code has been updated and has fixed bugs. updated version can be found here

The header file: mystring.h

#ifndef STRING_H_DEFINED
#define STRING_H_DEFINED

#define GLOBAL_MAX_CHAR_LIMIT 200

//dont need to include stdbool.h!
#define true 1
#define false 0
typedef int bool;

typedef struct{
    char * _str;
}sstring;

typedef struct{
    char _str[GLOBAL_MAX_CHAR_LIMIT];
}substr;

//functions declarations
sstring cstr2sstr(char _cstr[GLOBAL_MAX_CHAR_LIMIT]);
char sgetchar(sstring _str,int _pos);
substr strinput();
substr ssetchar(sstring _str,int _pos,char _ch);
substr sstrappend(sstring _str,char * _append);
substr ssubstr(sstring _str,int pos1,int len);
char * sstrval(sstring _str);
int cstrlen(const char * _str);
int sstrlen(sstring _str);
int sstrfind(int init,sstring _strvar,const char * _find);
sstring sstrreplace(sstring _str,char * _find,char * _repl);

#endif

mystring.c << to be included and compiled at once

#include "mystring.h"
#include<string.h>
#include<stdio.h>



char * sstrval(sstring _str){
    return _str._str;
}

int cstrlen(const char * _str){
    int i=0;
    while(1>0){
        if(_str[i]=='\0'){
            return i;
        }
        i++;
    }
}



int sstrlen(sstring _str){
    return cstrlen(sstrval(_str));
}

substr sstrappend(sstring _str,char * _append){
    int _len = sstrlen(_str),_len2=cstrlen(_append);
    char temp[_len+_len2];
    for(int i=0;i<_len+_len2;i++){
        temp[i] = _str._str[i];
        if(i>=_len){
            temp[i] = _append[i-_len];
        }
    }
    substr ret;
    for(int i=0;i<cstrlen(temp);i++){
        ret._str[i] = temp[i];
    }
    ret._str[_len+_len2] = '\0';
    return ret;
}


int sstrfind(int init,sstring _strvar,const char * _find){
    const char * _str;
    _str = _strvar._str;
    int _len1 = cstrlen(_str);
    int _len2 = cstrlen(_find);
    int matching = 0;
    
    //some wierd conditions check [user, are u fooling the function ?]
    if(_len2>_len1||init<0||init>_len1-1||_len2==0){
        return -1;
    }
    
    //the main finder
    for(int i=init;i<_len1+1;i++){
        if(_str[i]==_find[0]){
            for(int z=0;z<_len2+1;z++){
                if(matching==_len2){
                    return i;
                }
                else if(_str[i+z]==_find[z]){
                    matching+=1;
                }
                else{
                    matching=0;
                    break;
                }
            }
        }
    }
    return -1;
}




substr ssubstr(sstring _str,int pos1,int len){
    substr self;
    
    if(pos1<0||len<1||sstrlen(_str)<1||pos1+len>sstrlen(_str)){
        return self;
    }
    
    char a[GLOBAL_MAX_CHAR_LIMIT];
    
    for(int i=0;i<GLOBAL_MAX_CHAR_LIMIT;i++){
        a[i] = '\0';
    }
    
    
    if(pos1==0){
        for(int i=0;i<len;i++){
            a[i] = _str._str[i];
        }
    }
    
    
    for(int i=pos1;i<pos1+len;i++){
        a[i-pos1] = _str._str[i];
    }
    substr b;
    
    for(int i=0;i<GLOBAL_MAX_CHAR_LIMIT;i++){
        b._str[i] = '\0';
    }
    
    for(int i=0;i<=GLOBAL_MAX_CHAR_LIMIT;i++){
        if(i>GLOBAL_MAX_CHAR_LIMIT){
            return self;
        }
        b._str[i] = a[i];
    }
    return b;
}

substr ssetchar(sstring _str,int _pos,char _ch){
    substr tmp;
    
    //nullify the string buffer
    for(int i=0;i<GLOBAL_MAX_CHAR_LIMIT;i++){
        tmp._str[i]='\0';
    }
    
    if(_pos<0){
        return tmp;
    }
    
    //copy the string buffer and set the char of _pos as _ch
    for(int i=0;i<sstrlen(_str);i++){
        tmp._str[i]=_str._str[i];
        if(i==_pos){
            tmp._str[i]=_ch;
        }
    }
    return tmp;
}

char sgetchar(sstring _str,int _pos){
    char _ret;
    _ret = '\0';
    if(_pos<0){
        return _ret;
    }
    _ret = _str._str[_pos];
    return _ret;
}

substr strinput(){
    substr temp;
    fgets(temp._str,GLOBAL_MAX_CHAR_LIMIT,stdin);
    temp._str[cstrlen(temp._str)-1] = '\0';
    return temp;
}

sstring sstrreplace(sstring _str,char * _find,char * _repl){
    //duplicate of _str
    sstring _dup = _str;
    
    //temp str's
    sstring _tmp,_tmp2;
    
    substr self,tmp;
    
    
    int _lens = strlen(_str._str);
    int _lenf = strlen(_find);  int _lenr = strlen(_repl);
    
    
    //current limit - idk why but if _lenr > 7 WIERD THINGS HAPPEN so return original string
    if(_lenr>7){
        return _dup;
    }
    
    int temp=0,nottoappend=0;
    
    char tmpstr[GLOBAL_MAX_CHAR_LIMIT];
    temp=sstrfind(0,_str,_find);
    if(temp==-1){
        return _dup;
    }
     
    
    int tmpint=0,num=1;
    while(1>0){
        temp = sstrfind(0,_dup,_find);
        if(temp==-1){
            //incase of char buffering
            printf("%c\b \b",_dup._str[sstrlen(_dup)-1]);
            return _dup;
        }else{
        if(temp==sstrlen(_dup)-1){
            _dup._str = ssubstr(_dup,0,sstrlen(_dup)-1)._str;
            _dup._str = sstrappend(_dup,_repl)._str;
            //incase of char buffering
            printf("%c\b \b",_dup._str[0]);
            return _dup;
        }
        if(_lenr==0){
            _tmp._str = ssubstr(_dup,0,temp)._str;
            _tmp2._str = ssubstr(_dup,temp+_lenf,sstrlen(_dup)-temp-_lenf)._str;
            _dup._str = sstrappend(_tmp,_tmp2._str)._str;
            
        }else{
        _tmp._str = ssubstr(_dup,0,temp)._str;
        _tmp2._str = ssubstr(_dup,temp+_lenf,sstrlen(_dup)-temp-_lenf)._str;
        _dup._str = sstrappend(_tmp,_repl)._str;
        _dup._str = sstrappend(_dup,_tmp2._str)._str;
        }
        }
    }
}


sstring cstr2sstr(char _cstr[GLOBAL_MAX_CHAR_LIMIT]){
    sstring _ret;
    _ret._str = "";
    for(int i=0;i<cstrlen(_cstr);i++){
        _ret._str = sstrappend(_ret," ")._str;
    }
    for(int i=0;i<cstrlen(_cstr);i++){
        _ret._str = ssetchar(_ret,i,_cstr[i])._str;
        //incase of char buffering
        printf("%c\b%c\b \b",_cstr[i],_ret._str[i]);
    }
    return _ret;
}

exampleusage.c

#include<stdio.h>
#include "mystring.h"


int main(){
    
    int len1,find;
    sstring var1,var2,var3;
    char chr;

    
    printf("Enter your name: ");
    //strinput!
    var1._str = strinput()._str;
    
    //length of string
    len1 = sstrlen(var1);
    printf("\nYour name's Length is: %d",len1);
    
    //replacing all spaces with underscores
    var2._str = sstrreplace(var1," ","_")._str;
    printf("\nYour url might look like : '%s'",var2);
    
    //with no spaces
    var2._str = sstrreplace(var1," ","")._str;
    printf("\nConJusted Name: %s",var2);
    
    //appending " is a good person full of honesty and great behaviour!"
    var2._str = sstrappend(var1," is a good person full of honesty and great behaviour!")._str;
    printf("\nGood about you: %s",var2);
    
    //finding space!
    find = sstrfind(0,var1," ");
    printf("\nFirst space in your name is in %d charachter",find);
    
    //substrings!
    find = sstrfind(0,var1," ");
    var2._str = ssubstr(var1,0,find)._str;
    printf("\nYour first name: %s",var2);
    var2._str = ssubstr(var1,find+1,len1-find-1)._str;
    printf("\nYour last name: %s",var2);
    
    //setting chars!
    //set first char to 'F'
    var2._str = ssetchar(var1,0,'F')._str;
    printf("\nYour name with first char as 'F': %s",var2);
    
    //getting chars!
    //get last char of name!
    chr = sgetchar(var1,sstrlen(var1)-1);
    printf("\nYour name's last char is '%c'",chr);
}
\$\endgroup\$
1
  • \$\begingroup\$ This code has been updated with bugfixes and suggestions! thanks all for reviewing this code. updated code \$\endgroup\$
    – Pear
    Nov 4, 2021 at 7:13

2 Answers 2

8
\$\begingroup\$

Don't reimplement bool

Just #include <stdbool.h>. The problem with reimplementing it is that it will now conflict with the definitions from <stdbool.h>, so someone using both <stdbool.h> and your string library will have a problem.

Even worse, you are not using bool, true or false anywhere in your own code, so it was useless to define them to begin with.

Don't reimplement standard library functions

Why implement cstrlen() when you can just use the standard library's strlen()? In fact, you call strlen() yourself inside sstrreplace(). Related to this:

The result of strlen() is a size_t

An int might not be large enough to represent the size of all strings on your platform. The proper type to store the length of a string is size_t.

Buffer overflows

In sstrappend() the concatenation of two strings can be longer than GLOBAL_MAX_CHAR_LIMIT. You don't check against that limit when copying temp into ret._str. This means your program has a buffer overflow that might be exploitable.

Note that just ensuring you never write more than GLOBAL_MAX_CHAR_LIMIT characters into ret._str might fix the buffer overflow, but still is problematic. Consider you might want to create a full pathname by concatenating a directory name and a filename, and the result is longer than can be stored. If you return a truncated filename, the program might open the wrong file, which might itself be a security issue.

Incorrect copying of sstrings

In sstrreplace(), I see:

sstring _dup = _str;

This will not actually create a copy of the string itself, it will only create a copy of the pointer to the string, because afterwards the following is true: _dup._str == _str._str.

Inconsistent use of underscores

Some variables are prefixed with an underscore, some are not. I don't see any pattern to it. Also, some uses of leading underscores are reserved in C, I recommend you don't use them as prefixes at all.

Work with the standard library instead of against it

The standard string functions in C leave a lot to be desired, so creating a library to add functionality like search-and-replace is great. But I recommend you just make it work with regular C strings, and have it return regular C strings. There are several ways in which you can do that:

  • Have your function allocate memory for the result, and return a pointer to that memory after storing the result in it.
  • Have the caller specify a pointer to and the size of a buffer where your function can write the results to.

Also, just use standard library functions inside your own functions when appropriate. For example, I would rewrite sstrappend() like so:

char *sstrappend(const char *str1, const char *str2) {
    size_t len1 = strlen(str1);
    size_t len2 = strlen(str2);

    char *result = malloc(len1 + len2 + 1);
    if (!result) {
        /* Could not allocate memory, let the caller deal with it. */
        return NULL;
    }

    memcpy(result, str1, len1);
    memcpy(result + len1, str2, len2);
    result[len1 + len2] = '\0';

    return result;
}
\$\endgroup\$
10
  • \$\begingroup\$ Your suggestion is truly great ! i use underscores for avoiding the confusion between global variable , temp variable or local variable used inside a function. You are right there are reserved keywords like __MINGW.. etc etc but i think that using custom names might not affect this. Yeah you are right about the buffer overflow and incorrect copying which has caused bugs [ i mentioned that making length of replacing string cause weird things to happen ]! but as u have said to use malloc, the user needs to use free(), else memory leak could happen, to avoid this i used my functions to do so! \$\endgroup\$
    – Pear
    Oct 17, 2021 at 13:45
  • \$\begingroup\$ But with your way you can only return fixed size buffers, that are either almost always bigger than necessary, or they are not big enough. I think that is more trouble than it is worth, and I personally would rather use C++ then, as this issue is nicely solved by std::string. \$\endgroup\$
    – G. Sliepen
    Oct 17, 2021 at 14:53
  • \$\begingroup\$ it wont! yeah i also would like to use c++, but wanna build it in c!. you can check the length of returned var using strlen() <- a default function! \$\endgroup\$
    – Pear
    Oct 17, 2021 at 15:01
  • \$\begingroup\$ if u see the function code line by line you would be surprised to see that i perform operations on char arrays[] and return char arrays[] stored in type substr, But in the code i get them assigned to sstring._str which is a pointer . see mystring.h This is a conversion between char[] to char * without returning its address, so the length is not fixed. however, using char arrays[] need a fixed length which is the GLOBAL_MAX_CHAR_LIMIT contains \$\endgroup\$
    – Pear
    Oct 17, 2021 at 15:05
  • \$\begingroup\$ I recommend that you try setting GLOBAL_MAX_CHAR_LIMIT to something low like 10, and then try to run your example program again, if possible using Valgrind to ensure writes out of bounds are caught as soon as possible. \$\endgroup\$
    – G. Sliepen
    Oct 17, 2021 at 15:09
0
\$\begingroup\$

This declaration is a problem:

 substr strinput();

Firstly, we should always specify what arguments a function takes (i.e. make it a prototype). In this case, it appears it should take no arguments, so write (void) as the argument list.

Secondly, we've given it a name that's not ours to assign. Every identifier beginning with the three letters str is reserved for standard library use, so this is at risk of causing problems for programs that also include <string.h> (which is rather likely).


Also on the subject of naming, many variables are declared beginning with _. Those are also reserved identifiers - keep clear of those, too.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.