Allocated Dynamically Array of pointers - arrays

i'm really stuck.
I pust a big part of code you can try to run it on in online c compiler. My problem is weird, every time after 2 iteration i lost the data on spliter[0][0] when i mean "lost" is modified, for better understand please look what is printing it.
Inside
Inside the loop that iterates I wanted to see if the characters were well allocated in the present time and this is the case, only afterwards when I want to check it is impossible for me to do anything.
My program boils down to separating one character string according to another and dynamically allocating these character strings in my split. Each separator character counts as separator.
I have already prepared the test in comment. I really need help, too long time im stuck here..
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int is_c(char c, char *cha) {
while (*cha) {
if (*cha == c) {
return (1);
}
cha++;
}
return (0);
}
int ct_str(char *str, char *cha) {
int sw;
int nbr;
char item;
nbr = 0;
while (*str) {
if (!(is_c(*str, cha)) && *str >= 33 && *str <= 127 && sw == 1) {
sw = 0;
nbr+=1;
}
str++;
while (is_c(*str, cha)) {
str++;
sw = 1;
}
}
return (nbr);
}
int no_blk(char *str, int position, char *cha) {
while (!is_c(str[position], cha)) {
if (str[position] >= 33 && str[position] <= 127)
return (1);
position++;
}
return (0);
}
int get_size(char *str, int position, char *cha) {
int item;
item = position;
int j;
j = 0;
while (str[item]) {
if (is_c(str[item], cha))
return (j);
item++;
j++;
}
return (0);
}
void split_this(char **split, char *str, char *cha) {
int i;
int level;
int sw;
int e;
level = 0;
i = 0;
int item = 0;
int element = 0;
while(str[i + 1]) {
e = 0;
while(is_c(str[i], cha)) {
sw = 1;
i++;
}
if(sw == 1 && (!is_c(str[i], cha)) && no_blk(str, i, cha)) {
split[level] = (char*)malloc(sizeof(char) * get_size(str, i, cha) + 1);
e = i;
//printf("%i \n", get_size(str, i, cha));
while(e - i < get_size(str, i, cha)) {
split[level][e - i] = str[e];
//printf("%c", split[level][e - i]);
split[level][(e + 1) - i] = '\0';
e++;
}
printf("%c", split[0][0]);
sw = 0;
level++;
}
i++;
}
free(split);
/*
int it = 0;
int ee;
while(split[it]) {
ee = 0;
while(split[it][ee]) {
printf("%c", split[it][ee]);
ee++;
}
it++;
}
*/
}
void ft_split(char *str, char *cha) {
char **spliter = NULL;
spliter = (char**)malloc(sizeof(char) * ct_str(str, cha) + 1);
split_this(spliter, str, cha);
}
int main(int argc, char **argv) {
//if (argc == 3)
//ft_split(argv[1], argv[2]);
ft_split("%%am%s%s%ss%%s%%%qsdqsd%%%on%vs%lre%" , "%%");
return (0);
}

Related

Why is my solution for Super Reduced String(HackerRank) question working fine on my computer but giving wrong answers in HackerRank?

When I run my code in Hackerrank it fails 6/16 test cases but when I try the same test cases on my computer it works fine.
This is the code that I run on my computer:(I use Clion as ide and the latest MinGW as compiler.)
I initialize the string with one of the test cases that fail on HackerRank.
#include <string.h>
#include <stdio.h>
//#include <stdlib.h>
char* superReducedString(char* s);
int contain(char *S,char find);
void copyWithout(char *S,char *T,char trash);
int countWithout(char *S,char trash);
int findSize(char *S);
void fillString(char *S,char filler);
int main(){
char s[] = {"ppffccmmssnnhhbbmmggxxaaooeeqqeennffzzaaeeyyaaggggeessvvssggbbccnnrrjjxxuuzzbbjjrruuaaccaaoommkkkkxx"};
char *result = superReducedString(s);
printf("%s",result);
}
int findSize(char *S){
int i = 0;
while(*(S+i) != '\0'){
i++;
}
return i;
}
void fillString(char *S,char filler){
int i = 0;
while(*(S+i) != '\0'){
*(S+i) = filler;
i++;
}
}
void copyWithout(char *S,char *T,char trash){
fillString(T,'0');
int i = 0;
int count = 0;
while(*(S+i) != '\0'){
if(*(S+i) != trash){
*(T+count) = *(S+i);
count++;
}
i++;
}
}
int countWithout(char *S,char trash){
int i = 0;
int count = 0;
while(*(S+i) != '\0'){
if(*(S+i) != trash){
count++;
}
i++;
}
return count;
}
int contain(char *S,char find){
int i = 0;
int flag = 0;
while(*(S+i) != '\0'){
if(*(S+i) == find){
flag = 1;
}
i++;
}
return flag;
}
char* superReducedString(char* s){
static char empty[] = "Empty String";
static char result[1024];
int flag = 1;
char temp[findSize(s)];
fillString(temp,'0');
int i,j;//Loop variable.
i = 0;
while(*(s + i) != '\0'){
j = 0;
//Checking if adjacent numbers is same. If it is changing them to '0'.
while(s[j] != '\0') {
if (s[j] == s[j + 1]) {
*(s + j) = '0';
*(s + j + 1) = '0';
}
j++;
}
if(contain(s,'0') == 0){ //If there is no zero in original string that means nothing changed.
return s;
}else{
copyWithout(s,temp,'0');//If there are zeros in it, copy it to a temp char array without zeros.
}
strcpy(s,temp);//Copy temp to s again for swapping.
i++;
}
int count = countWithout(s,'0'); //Calculate the size of original string without zeros.
char finalString[count];//Initialize a new string with the calculated size.
copyWithout(s,finalString,'0'); //Copy original string to finalString without zeros to obtain a clear zeroless string.
strcpy(result,finalString);//copy finalstring to static result string to return it.
i = 0;
while(*(result+i) != '\0'){ //Check if result string consists of zeroes. If it is code will return empty string.
if(*(result+i) != '0'){
flag = 0;
}
i++;
}
if(flag == 0){
return result;
}else{
return empty;
}
}
and this is the code that I run on HackerRank:
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* superReducedString(char* s);
int contain(char *S,char find);
void copyWithout(char *S,char *T,char trash);
int countWithout(char *S,char trash);
int findSize(char *S);
void fillString(char *S,char filler);
char* readline();
int main()
{
FILE* fptr = fopen(getenv("OUTPUT_PATH"), "w");
char* s = readline();
char* result = superReducedString(s);
fprintf(fptr, "%s\n", result);
fclose(fptr);
return 0;
}
char* readline() {
size_t alloc_length = 1024;
size_t data_length = 0;
char* data = malloc(alloc_length);
while (true) {
char* cursor = data + data_length;
char* line = fgets(cursor, alloc_length - data_length, stdin);
if (!line) {
break;
}
data_length += strlen(cursor);
if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') {
break;
}
alloc_length <<= 1;
data = realloc(data, alloc_length);
if (!data) {
data = '\0';
break;
}
}
if (data[data_length - 1] == '\n') {
data[data_length - 1] = '\0';
data = realloc(data, data_length);
if (!data) {
data = '\0';
}
} else {
data = realloc(data, data_length + 1);
if (!data) {
data = '\0';
} else {
data[data_length] = '\0';
}
}
return data;
}
int findSize(char *S){
int i = 0;
while(*(S+i) != '\0'){
i++;
}
return i;
}
void fillString(char *S,char filler){
int i = 0;
while(*(S+i) != '\0'){
*(S+i) = filler;
i++;
}
}
void copyWithout(char *S,char *T,char trash){
fillString(T,'0');
int i = 0;
int count = 0;
while(*(S+i) != '\0'){
if(*(S+i) != trash){
*(T+count) = *(S+i);
count++;
}
i++;
}
}
int countWithout(char *S,char trash){
int i = 0;
int count = 0;
while(*(S+i) != '\0'){
if(*(S+i) != trash){
count++;
}
i++;
}
return count;
}
int contain(char *S,char find){
int i = 0;
int flag = 0;
while(*(S+i) != '\0'){
if(*(S+i) == find){
flag = 1;
}
i++;
}
return flag;
}
char* superReducedString(char* s){
static char empty[] = "Empty String";
static char result[1024];
int flag = 1;
char temp[findSize(s)];
fillString(temp,'0');
int i,j,k;//Loop variable.
i = 0;
while(*(s + i) != '\0'){
j = 0;
while(s[j] != '\0') {
if (s[j] == s[j + 1]) {
*(s + j) = '0';
*(s + j + 1) = '0';
}
j++;
}
if(contain(s,'0') == 0){
return s;
}else{
// printf("temp0 = %s s0 = %s\n",temp,s);
copyWithout(s,temp,'0');
// printf("temp1 = %s s1 = %s\n",temp,s);
}
//printf("%s\n",temp);
strcpy(s,temp);
i++;
}
int count = countWithout(s,'0');
char finalString[count];
copyWithout(s,finalString,'0');
strcpy(result,finalString);
i = 0;
while(*(result+i) != '\0'){
if(*(result+i) != '0'){
flag = 0;
}
i++;
}
if(flag == 0){
return result;
}else{
return empty;
}
}
The only difference is main function and the functions that HackerRank uses for getting input.
I don't know if this helps but sometimes my code can give wrong answers for same input.
What I mean is:
input = "acdqglrfkqyuqfjkxyqvnrtysfrzrmzlygfveulqfpdbhlqdqrrqdqlhbdpfqluevfgylzmrzrfsytrnvqyxkjfquyqkfrlacdqj"
While it should give "acdqgacdqj" as answer, it gives "acdqgacdqjÑ"
The last char randomly changes.
But for other inputs no matter how many times I run it it gives the correct answer on my computer.
char temp[findSize(s)]; fillString(temp,'0'); is invalid. In fillString you iteratate until the element is equal to '\0'. temp is uninitialized - you can't expect it to have any certain value (and even reading an uninitialized value is undefined behavior).
In char finalString[count]; count is too small - it doesn't account for zero terminating character. copyWithout(s,finalString,'0'); is not copying zero terminating character. Which results in strcpy(result,finalString); accessing array out-of-bounds when searching for.... zero terminating character.
When working with C string you usually see a magical + 1 everywhere in the code.
Advices:
Prefer not use variable length arrays (arrays where the size expression is not a constant expression). Prefer using dynamic allocation.
findSize is just strlen...
fillString is just memset(string, value, strlen(string));
When using a compiler, always enable all options. When using gcc, you could use gcc -g -Wall -Wextra -fsanitize=address sourcefile.c - sanitize will allow to really fast find all out-of-bounds accesses on stack variables. Use valgrind to find dynamic allocation leaks.
I advise to change order of argument in copyWithout to (destination, source, fill) so it's the same as strcpy(destination, source) - ie. destination is first.
Seems like fixing parts of code to:
char* superReducedString(char* s){
...
// char temp[findSize(s)];
char temp[findSize(s) + 1];
// fillString(temp,'0');
memset(temp, '0', findSize(s));
temp[findSize(s)] = '\0';
...
char finalString[count + 1];//Initialize a new string with the calculated size.
memset(finalString, '0', count);
finalString[count] = '\0';
}
is enough for me to -fsanitize to stop erroring.
I have no idea where exactly your bug is, but it is quite clear from the output that you are using uninitialised memory. And on your computer, that uninitialised memory contains a zero by pure coincidence, and on the computer used for the test it doesn't.
Generally if you have a problem "it works on computer A but not on computer B" then very often undefined behaviour in your code is the answer, and here it is most like uninitialised memory.

Why does variable loss its value after end of block?

I have written a code to test a substring operation.
test.c
#include "compiler_expression.h"
#include <stdio.h>
int main()
{
char *s1 = "(Hello) World";
int l = 0;
printf("%s\n", substr_limits(s1, '(', ')', &l));
return 0;
}
compiler_expression.h
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
// strcpy(s1, s2) Copies s2 into s1
// strcat(s1, s2) Concatenates s2 onto the end of s1
// strlen(s1) Returns the length of s1
// strcmp(s1, s2) Returns 0 if s1 and s2 are the same; less than 0 if s1<s2; greater
// than 0 if s1>s2
// strchr(s1, ch) Returns a pointer to the first occurrence of ch in s1
// strstr(s1, s2) Returns a pointer to the first occurrence of s2 in s1
char * substr(char *str, int begin, int end)
{
if (begin<0 || end>strlen(str))
{
printf("\nError: arguments (begin or end) is out of index\n");
exit(1);
}
char *res = malloc(end-begin);
for (int i=begin; i<end; i++)
{
res[i-begin] = str[i];
}
return res;
}
char *substr_limits(char *str, char begin_char, char end_char, int *no_limit)
{
*no_limit = 1;
if (begin_char==end_char)
{
printf("%s\n", "::begin char is equal to end char");
int begin_limit = 0;
int end_limit = 0;
int limit_num = 0;
for (int i=0;i<strlen(str);i++)
{
printf("%s\n", "::begin first loop");
if (str[i]!=begin_char) continue;
printf("%s\n", "::limit char found");
if (limit_num==1)
{
printf("%s\n", "::limit_num==1");
end_limit = i;
char *res = malloc(end_limit-begin_limit-1);
for (int j=begin_limit+1;j<end_limit;j++)
{
printf("%s%c\n", "::char==", str[j]);
res[j-begin_limit] = str[j];
printf("%s%c\n", "::res_char==", res[j-begin_limit]);
}
printf("%s%s\n", "::result==", res);
return res;
}
*no_limit = 0;
limit_num = 1;
begin_limit = i;
}
if (limit_num!=0) {
printf("\nError: The limits are not justified\n");
exit(1);
}
if (*no_limit==1) {
return str;
}
}
else
{
int begin_limit = 0;
int end_limit = 0;
int limit_num = 0;
for (int i=0;i<strlen(str);i++)
{
if (str[i]!=begin_char&&str[i]!=end_char) continue;
*no_limit = 0;
if (str[i]==begin_char)
{
limit_num += 1;
if (limit_num==1) begin_limit = i;
}
else if (str[i]==end_char)
{
limit_num -= 1;
if (limit_num==0)
{
end_limit = i;
char *res = malloc(end_limit-begin_limit);
for (i=begin_limit+1;i<end_limit;i++)
{
res[i-begin_limit] = str[i];
}
return res;
}
}
}
if (limit_num!=0) {
printf("\nError: The limits are not justified\n");
exit(1);
}
if (*no_limit==1) {
return str;
}
}
}
at the function (substr_limits), there is a problem: when the condition (begin_char==end_char) is true and after executing all code, I noticed at last operations before executing (return res;) that the code is run in the correct way and get all specified characters from (str) into (res) variable but after ending block of (for loop), I have noticed that the value of (res) is blank string which makes also the returned value is blank string, I was trying to solve problem by writing this code:
char *res = malloc(end_limit-begin_limit-1);
for (int j=begin_limit+1;j<end_limit;j++)
{
printf("%s%c\n", "::char==", str[j]);
res[j-begin_limit] = str[j];
printf("%s%c\n", "::res_char==", res[j-begin_limit]);
if (j==end_limit-1) {
printf("%s%s\n", "::result==", res);
return res;
}
}
But the problem still exists!
Bug #1. Instead of this:
char *res = malloc(end-begin);
for (int i=begin; i<end; i++)
{
res[i-begin] = str[i];
}
This:
char *res = malloc(end-begin+1); //+1 for null char
for (int i=begin; i<end; i++)
{
res[i-begin] = str[i];
}
res[end-begin] = '\0'; // null terminate the string that gets returned
I don't see substr getting invoked, but I see other variations of this string copy pattern missing the null char in your limits function.
More to come as I keep looking at the code....

Creating list of ip addresses over a specific range in C

I am writing a tool to scan all the nodes on a network but I have ran in to a problem. I'm writing the tool in C but I'm new to the language so I'm not sure how the iterate through the address range.
The user will give the argument 192.168.*.* and it will create every IP address in that range, e.g. 192.168.1.1, 192.168.1.2, 192.168.1.3 and then eventually 192.168.2.1, 192.168.2.2, 192.168.2.3 etc.
My previous code was:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void scanner(int s)
{
char addr[20];
for (int i = 0; i < 255; ++i)
{
sprintf(addr, "192.168.%d.%d", s, i);
printf("%s\n", addr);
}
}
int main()
{
for (int i = 0; i < 255; ++i)
{
scanner(i);
}
return 0;
}
But I don't know how to run this from the user input.
You can take the inputs from the user using the scanf function. I have updated your code to use the same -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int addr_byte_0;
int addr_byte_1;
void scanner(int s)
{
char addr[200];
int i;
for (i = 0; i < 255; ++i)
{
sprintf(addr, "%d.%d.%d.%d", addr_byte_0, addr_byte_1, s, i);
printf("%s\n", addr);
}
}
int main()
{
int i;
//printf("Enter the first byte of the address: ");
scanf ("%d", &addr_byte_0);
//printf("Enter the second byte of the address: ");
scanf ("%d", &addr_byte_1);
for (i = 0; i < 255; ++i)
{
scanner(i);
}
return 0;
}
Also, as per C standards you cannot declare a variable inside the for loop. Hence I have moved the declaration out of the for loop. Hope this helps!
Inspired by (e.g. python-) generators, my solution doesn't perform dynamic memory allocation and and has constant memory consumption. I don't like that I currently rely on a do while loop. Also the explicit check for ig->num_wildcards == 0 is ugly. Anyways:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define IP_OCTETS 4
#define MAX_UCHAR 255
typedef struct {
int wildcard_pos[IP_OCTETS];
int num_wildcards;
int counter[IP_OCTETS];
int octet[IP_OCTETS];
} ip_generator;
char* mystrsep(char** stringp, const char* delim)
{
char* start = *stringp;
char* p;
p = (start != NULL) ? strpbrk(start, delim) : NULL;
if (p == NULL)
{
*stringp = NULL;
}
else
{
*p = '\0';
*stringp = p + 1;
}
return start;
}
void init_ip_gen(ip_generator *ig, char* ip_mask)
{
char *token, *string;
char* ip_mask_ptr = ip_mask;
const char delimiters[] = ".";
int i = 0;
while ((token = mystrsep(&ip_mask_ptr, delimiters)) != NULL)
{
ig->wildcard_pos[i] = -1;
if (strcmp(token, "*") == 0)
{
ig->wildcard_pos[ig->num_wildcards] = i;
ig->counter[ig->num_wildcards] = 1;
ig->num_wildcards++;
}
else
{
ig->octet[i] = atoi(token);
}
i++;
}
}
int ig_next(ip_generator *ig)
{
int i;
int carry = 1;
if (ig->num_wildcards == 0)
{
return 0;
}
for (i = ig->num_wildcards - 1; i >= 0; i--)
{
if (carry == 1)
{
if (ig->counter[i] == MAX_UCHAR)
{
ig->counter[i] = 1;
}
else
{
ig->counter[i]++;
carry = 0;
}
}
if (carry == 0)
{
break;
}
if (i == 0 && carry == 1)
{
return 0;
}
}
return 1;
}
void generate_ip(ip_generator *ig, char *ip)
{
int i;
int j = 0;
int oct[IP_OCTETS];
for (i = 0; i < IP_OCTETS; i++)
{
if (i == ig->wildcard_pos[j])
{
oct[i] = ig->counter[j];
j++;
}
else
{
oct[i] = ig->octet[i];
}
}
sprintf(ip, "%d.%d.%d.%d", oct[0], oct[1], oct[2], oct[3]);
}
int main()
{
char ip_mask[] = "192.*.10.*";
//char ip_mask[] = "192.1.10.123";
ip_generator ig;
memset(&ig, 0, sizeof(ig));
init_ip_gen(&ig, ip_mask);
char ip[32];
memset(ip, 0, sizeof(ip));
do
{
generate_ip(&ig, ip);
printf("%s\n", ip);
} while (ig_next(&ig));
return 0;
}

Inserting a value into an array and arranging array according to value c

char num = '5';
strcpy(array, "2,3,7,9")
Hi guys, any ideas if want to insert 5 into the array according to the value which will result in, how would i go about doing this?
array = "2,3,5,7,9"
#include <stdio.h>
#include <string.h>
void insert_string(char *target, const char *to_insert, int index) {
int count = 0;
int i;
int move_dst;
int insert_comma = 0;
int to_len = strlen(to_insert);
if (index < 0) index = 0;
if (index <= 0) {
i = 0;
} else {
for (i = 0; target[i] != '\0'; i++) {
if (target[i] == ',') {
count++;
if (count >= index) {
i++;
break;
}
}
}
}
/* i is where to insert the string */
if (target[i] == '\0') {
/* the insertion target was end of the string */
target[i] = ',';
target[++i] = '\0';
}
move_dst = i + to_len;
if (target[i] != '\0') {
/* the sequence continues after insertion point */
move_dst++;
insert_comma = 1;
}
memmove(&target[move_dst], &target[i], strlen(&target[i]) + 1); /* copy includes termination '\0' */
memcpy(&target[i], to_insert, to_len);
if (insert_comma) target[i + to_len] = ',';
}
int main(void) {
char array[1024];
char num = '5';
char num_string[2] = {num, '\0'};
int c = 2;
strcpy(array, "2,3,7,9");
puts(array);
insert_string(array, num_string, c);
puts(array);
return 0;
}

Check substring exists in a string in C

I'm trying to check whether a string contains a substring in C like:
char *sent = "this is my sample example";
char *word = "sample";
if (/* sentence contains word */) {
/* .. */
}
What is something to use instead of string::find in C++?
if (strstr(sent, word) != NULL) {
/* ... */
}
Note that strstr returns a pointer to the start of the word in sent if the word word is found.
Use strstr for this.
https://cplusplus.com/reference/cstring/strstr
So, you'd write it like..
char *sent = "this is my sample example";
char *word = "sample";
char *pch = strstr(sent, word);
if(pch)
{
...
}
Try to use pointers...
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "String1 subString1 Strinstrnd subStr ing1subString";
char sub[] = "subString";
char *p1, *p2, *p3;
int i=0,j=0,flag=0;
p1 = str;
p2 = sub;
for(i = 0; i<strlen(str); i++)
{
if(*p1 == *p2)
{
p3 = p1;
for(j = 0;j<strlen(sub);j++)
{
if(*p3 == *p2)
{
p3++;p2++;
}
else
break;
}
p2 = sub;
if(j == strlen(sub))
{
flag = 1;
printf("\nSubstring found at index : %d\n",i);
}
}
p1++;
}
if(flag==0)
{
printf("Substring NOT found");
}
return (0);
}
You can try this one for both finding the presence of the substring and to extract and print it:
#include <stdio.h>
#include <string.h>
int main(void)
{
char mainstring[]="The quick brown fox jumps over the lazy dog";
char substring[20], *ret;
int i=0;
puts("enter the sub string to find");
fgets(substring, sizeof(substring), stdin);
substring[strlen(substring)-1]='\0';
ret=strstr(mainstring,substring);
if(strcmp((ret=strstr(mainstring,substring)),substring))
{
printf("substring is present\t");
}
printf("and the sub string is:::");
for(i=0;i<strlen(substring);i++)
{
printf("%c",*(ret+i));
}
puts("\n");
return 0;
}
And here is how to report the position of the first character off the found substring:
Replace this line in the above code:
printf("%s",substring,"\n");
with:
printf("substring %s was found at position %d \n", substring,((int) (substring - mainstring)));
My own humble (case sensitive) solution:
uint8_t strContains(char* string, char* toFind)
{
uint8_t slen = strlen(string);
uint8_t tFlen = strlen(toFind);
uint8_t found = 0;
if( slen >= tFlen )
{
for(uint8_t s=0, t=0; s<slen; s++)
{
do{
if( string[s] == toFind[t] )
{
if( ++found == tFlen ) return 1;
s++;
t++;
}
else { s -= found; found=0; t=0; }
}while(found);
}
return 0;
}
else return -1;
}
Results
strContains("this is my sample example", "th") // 1
strContains("this is my sample example", "sample") // 1
strContains("this is my sample example", "xam") // 1
strContains("this is my sample example", "ple") // 1
strContains("this is my sample example", "ssample") // 0
strContains("this is my sample example", "samplee") // 0
strContains("this is my sample example", "") // 0
strContains("str", "longer sentence") // -1
strContains("ssssssample", "sample") // 1
strContains("sample", "sample") // 1
Tested on ATmega328P (avr8-gnu-toolchain-3.5.4.1709) ;)
This code implements the logic of how search works (one of the ways) without using any ready-made function:
public int findSubString(char[] original, char[] searchString)
{
int returnCode = 0; //0-not found, -1 -error in imput, 1-found
int counter = 0;
int ctr = 0;
if (original.Length < 1 || (original.Length)<searchString.Length || searchString.Length<1)
{
returnCode = -1;
}
while (ctr <= (original.Length - searchString.Length) && searchString.Length > 0)
{
if ((original[ctr]) == searchString[0])
{
counter = 0;
for (int count = ctr; count < (ctr + searchString.Length); count++)
{
if (original[count] == searchString[counter])
{
counter++;
}
else
{
counter = 0;
break;
}
}
if (counter == (searchString.Length))
{
returnCode = 1;
}
}
ctr++;
}
return returnCode;
}
I believe that I have the simplest answer. You don't need the string.h library in this program, nor the stdbool.h library. Simply using pointers and pointer arithmetic will help you become a better C programmer.
Simply return 0 for False (no substring found), or 1 for True (yes, a substring "sub" is found within the overall string "str"):
#include <stdlib.h>
int is_substr(char *str, char *sub)
{
int num_matches = 0;
int sub_size = 0;
// If there are as many matches as there are characters in sub, then a substring exists.
while (*sub != '\0') {
sub_size++;
sub++;
}
sub = sub - sub_size; // Reset pointer to original place.
while (*str != '\0') {
while (*sub == *str && *sub != '\0') {
num_matches++;
sub++;
str++;
}
if (num_matches == sub_size) {
return 1;
}
num_matches = 0; // Reset counter to 0 whenever a difference is found.
str++;
}
return 0;
}
Using C - No built in functions
string_contains() does all the heavy lifting and returns 1 based index. Rest are driver and helper codes.
Assign a pointer to the main string and the substring, increment substring pointer when matching, stop looping when substring pointer is equal to substring length.
read_line() - A little bonus code for reading the user input without predefining the size of input user should provide.
#include <stdio.h>
#include <stdlib.h>
int string_len(char * string){
int len = 0;
while(*string!='\0'){
len++;
string++;
}
return len;
}
int string_contains(char *string, char *substring){
int start_index = 0;
int string_index=0, substring_index=0;
int substring_len =string_len(substring);
int s_len = string_len(string);
while(substring_index<substring_len && string_index<s_len){
if(*(string+string_index)==*(substring+substring_index)){
substring_index++;
}
string_index++;
if(substring_index==substring_len){
return string_index-substring_len+1;
}
}
return 0;
}
#define INPUT_BUFFER 64
char *read_line(){
int buffer_len = INPUT_BUFFER;
char *input = malloc(buffer_len*sizeof(char));
int c, count=0;
while(1){
c = getchar();
if(c==EOF||c=='\n'){
input[count]='\0';
return input;
}else{
input[count]=c;
count++;
}
if(count==buffer_len){
buffer_len+=INPUT_BUFFER;
input = realloc(input, buffer_len*sizeof(char));
}
}
}
int main(void) {
while(1){
printf("\nEnter the string: ");
char *string = read_line();
printf("Enter the sub-string: ");
char *substring = read_line();
int position = string_contains(string,substring);
if(position){
printf("Found at position: %d\n", position);
}else{
printf("Not Found\n");
}
}
return 0;
}
The same will be achieved with this simpler code: Why use these:
int main(void)
{
char mainstring[]="The quick brown fox jumps over the lazy dog";
char substring[20];
int i=0;
puts("enter the sub string to find");
fgets(substring, sizeof(substring), stdin);
substring[strlen(substring)-1]='\0';
if (strstr(mainstring,substring))
{
printf("substring is present\t");
}
printf("and the sub string is:::");
printf("%s",substring,"\n");
return 0;
}
But the tricky part would be to report at which position in the original string the substring starts...
My code to find out if substring is exist in string or not
// input ( first line -->> string , 2nd lin ->>> no. of queries for substring
following n lines -->> string to check if substring or not..
#include <stdio.h>
int len,len1;
int isSubstring(char *s, char *sub,int i,int j)
{
int ans =0;
for(;i<len,j<len1;i++,j++)
{
if(s[i] != sub[j])
{
ans =1;
break;
}
}
if(j == len1 && ans ==0)
{
return 1;
}
else if(ans==1)
return 0;
return 0;
}
int main(){
char s[100001];
char sub[100001];
scanf("%s", &s);// Reading input from STDIN
int no;
scanf("%d",&no);
int i ,j;
i=0;
j=0;
int ans =0;
len = strlen(s);
while(no--)
{
i=0;
j=0;
ans=0;
scanf("%s",&sub);
len1=strlen(sub);
int value;
for(i=0;i<len;i++)
{
if(s[i]==sub[j])
{
value = isSubstring(s,sub,i,j);
if(value)
{
printf("Yes\n");
ans = 1;
break;
}
}
}
if(ans==0)
printf("No\n");
}
}
#include <stdio.h>
#include <string.h>
int findSubstr(char *inpText, char *pattern);
int main()
{
printf("Hello, World!\n");
char *Text = "This is my sample program";
char *pattern = "sample";
int pos = findSubstr(Text, pattern);
if (pos > -1) {
printf("Found the substring at position %d \n", pos);
}
else
printf("No match found \n");
return 0;
}
int findSubstr(char *inpText, char *pattern) {
int inplen = strlen(inpText);
while (inpText != NULL) {
char *remTxt = inpText;
char *remPat = pattern;
if (strlen(remTxt) < strlen(remPat)) {
/* printf ("length issue remTxt %s \nremPath %s \n", remTxt, remPat); */
return -1;
}
while (*remTxt++ == *remPat++) {
printf("remTxt %s \nremPath %s \n", remTxt, remPat);
if (*remPat == '\0') {
printf ("match found \n");
return inplen - strlen(inpText+1);
}
if (remTxt == NULL) {
return -1;
}
}
remPat = pattern;
inpText++;
}
}

Resources