Why does variable loss its value after end of block? - c

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....

Related

Substring exists in string in C

#include <stdio.h>
#include <string.h>
int main()
{
char str1[80] = "downtown", str2[20] = "town";
int len1 = 0, len2 = 0, i, j, count;
len1 = strlen(str1);
len2 = strlen(str2);
for (i = 0; i <= len1 - len2; i++) {
for (j = i; j < i + len2; j++) {
count = 1;
if (str1[j] != str2[j - i]) {
count = 0;
break;
}
}
if (count == 1) {
break;
}
}
if (count == 1) {
printf("True");
} else {
printf("False");
}
}
In the above code, I'm trying to solve this one without using string functions apart from strlen() which can be replaced with a simple while loop. Is there any other way of checking for consecutive characters like firstly checking if the character is in the string, and if the i index is in the next position and not randomly in the string.
Here is a very clean way to do it using a function. It assumes that both str and sub are proper C-strings and returns a pointer to first match and NULL if no match.
char *substr(const char *str, const char *sub) {
if (!*sub)
return str; // Empty string is substring of all strings
while (*str) {
const char *sub1 = sub;
const char *str1 = str;
while (*str1++ == *sub1++) {
if (!*sub1)
return (char *)str;
}
str++;
}
return NULL;
}
This function is identical to the standard function strstr(), present in the C Standard library and declared in <string.h>.
There are some problems in the posted code:
count is uninitialized and only set if the inner loop is reached, which will not be the case if len1 < len2. count should be intialized to 0 to handle this case properly. found would be a more informative name for this variable.
Furthermore, the statement count = 1; should be moved before the inner loop to handle the case of an empty substring.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "downtown", str2[] = "town";
int found = 0;
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
if (len1 >= len2) {
for (size_t i = 0; i <= len1 - len2; i++) {
found = 1;
for (size_t j = 0; j < len2; j++) {
if (str1[i + j] != str2[j]) {
found = 0;
break;
}
}
if (found) {
break;
}
}
}
if (found) {
printf("True\n");
} else {
printf("False\n");
}
return 0;
}
I did not readily see OP's error. See #chqrlie.
Minor: Use size_t i, not int to cope with long strings.
strlen(str1) runs down the entire string, even when not needed, so that is avoided.
Alternative:
Fixed a faulty case in #klutt otherwise good answer.
Added const for greater application.
Return beginning of match on success.
Simplified and test harness added.
I like the needle in a haystack identifiers
char* substr3(const char *haystack, const char *needle) {
while (*haystack) {
const char *htmp = haystack;
const char *ntmp = needle;
while (*htmp == *ntmp && *htmp) {
htmp++;
ntmp++;
}
if (!*ntmp) {
return (char*) haystack; // Beginning of match
}
haystack++;
}
return *needle ? NULL : (char *) haystack;
}
int main(void) {
printf("%s\n", substr3("ababc", "abc"));
printf("%s\n", substr3("abc", "abc"));
printf("%s\n", substr3("abd", "ab"));
printf("%s\n", substr3("abc", ""));
printf("%s\n", substr3("", ""));
printf("%p\n", substr3("a", "abc"));
printf("%p\n", substr3("aba", "abc"));
printf("%p\n", substr3("x", "ab"));
printf("%p\n", substr3("aaa", "ab"));
return 0;
}
Some tighter code
char* substr4(const char *haystack, const char *needle) {
do {
const char *htmp = haystack;
const char *ntmp = needle;
while (*htmp == *ntmp && *ntmp) {
htmp++;
ntmp++;
}
if (!*ntmp) {
return (char*) haystack; // Beginning of match
}
} while (*haystack++);
return NULL;
}
Simple && naive:
char *substr2(char *str, char *sub) {
if (!*sub) return str; // not needed: see the generated code.
for(; *str; str++) {
size_t pos;
for(pos=0; str[pos] ; pos++) {
if (str[pos] != sub[pos]) break;
}
if (!sub[pos]) return str;
}
return NULL;
}
Generally:
if you don't try to outsmart the compiler: you win.
fewer variables: you win
fewer conditions inside the loop: win
try to be smart: you'll lose
when all else fails: use KMP or BM search

Allocated Dynamically Array of pointers

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);
}

C exercise return information about first position

exercise in C:
write a function 'any' wchich returns information about position of first occurrence in s1 any lsign from s2. Return -1 when s1 doesnt includes signs from s2.
And my code is:
#include <stdio.h>
#include <stdlib.h>
int any(char s1[], char s2[]) {
int i, j;
int koniec;
for (i = 0; s2[i] != '\0'; i++) {
for (j = 0; s1[j] != '\0'; j++) {
if (s1[j] == s2[i]) {
koniec = j;
}
else
{
koniec = -1;
}
}
}
return koniec;
}
int main()
{
char w1[] = "Dominik";
char w2[] = "zcki";
int wynik;
wynik = any(w1, w2);
printf("%d", wynik);
return 0;
}
but it returns: -1
but should 3
what is wrong?
Just return the position when you find it and do not keep looping:
int any(char s1[], char s2[]) {
int i, j;
for (i = 0; s1[i] != '\0'; i++) {
for (j = 0; s2[j] != '\0'; j++) {
if (s1[i] == s2[j]) {
return j;
}
}
}
return -1;
}
The if statement within the inner loop
if (s1[j] == s2[i]) {
koniec = j;
}
else
{
koniec = -1;
}
Does not make a sense because the value of the variable koniec will be overwritten in the last iterations of the both loops.
Moreover due to the order of the loops you are searching in fact a character from the string s2 in the string s1 while you need to find the first character in s1 that is present in s2.
The function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stddef.h>
ptrdiff_t any( const char *s1, const char *s2 )
{
ptrdiff_t pos = -1;
for ( const char *p1 = s1; pos == -1 && *p1; ++p1 )
{
const char *p2 = s2;
while ( *p2 && *p2 != *p1 ) ++ p2;
if ( *p2 ) pos = p1 - s1;
}
return pos;
}
int main(void)
{
char w1[] = "Dominik";
char w2[] = "zcki";
printf( "%td\n", any( w1, w2 ) );
return 0;
}
The program output is
3
Indeed the first character from w1 that is present in w2 is the character 'i'. Pay attention to that positions start from 0.
#include <stdio.h>
#include <stdlib.h>
int any(char *s1, char *s2)
{
int koniec=0;
int j=0;
for (int i = 0; s1[i]!='\0'; i++)
{j=0;
while(s1[i]!=s2[j]&&s2[j]!='\0')
{
j++;
}
if(s2[j]!='\0')
{
return j;
}
}
return -1;
}
int main()
{
char w1[] = "Dominik";
char w2[] = "zcki";
printf("%d\n", any(w1, w2));
return 0;
}

Selection of unique characters

Please, help with the code.
Requirement:
Write a function my_union that takes two strings and returns, without doubles, the characters that appear in either one of the strings.
Example:
Input: "zpadinton" && "paqefwtdjetyiytjneytjoeyjnejeyj"
Output: "zpadintoqefwjy"
My code:
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
char *my_union(char *a, char *b) {
char *str;
// Algorithm for excluding nonunique characters from string a(given in
// parameters).
str[0] = a[0];
int k = 1;
str[k] = '\0';
for (int i = 1; a[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == a[i]) {
is = false;
break;
}
}
if (is) {
str[k] = a[i];
k++;
str[k] = '\0';
}
} // In this case we are excluding excess character 'n' from "zpadinton", so
// str is equal to "zpadinto".
// Algorithm for adding unique characters from array b(given in parameters)
// into str.
for (int i = 0; b[i] != '\0'; i++) {
bool is = true;
for (int j = 0; str[j] != '\0'; j++) {
if (str[j] == b[i]) {
is = false;
break;
}
}
if (is) {
strncat(str, &b[i], 1);
}
}
return str;
}
The first algorithm is almost identical with second, but it doesn't work(. Mb I messed up with memory, give some advice, pls.
If you mean, get the unique characters from two strings and store them into a new string, try this code ;
First, you must allocate a memory for str. In your code, str is not pointing allocated memory location, so you will probably get segmentation fault.
int contains(const char * str,char c)
{
for (int i = 0; i < strlen(str); ++i)
if(str[i] == c)
return 1;
return 0;
}
char * my_union(char *a, char*b)
{
char * res = (char*)malloc(sizeof(char)*(strlen(a) + strlen(b)));
int pushed = 0;
for (int i = 0; i < strlen(a); ++i)
{
if(!contains(res,a[i])){
res[pushed] = a[i];
pushed++;
}
}
for (int i = 0; i < strlen(b); ++i)
{
if(!contains(res,b[i])){
res[pushed] = b[i];
pushed++;
}
}
return res;
}
int main(int argc, char const *argv[])
{
char string1[9] = "abcdefgh";
char string2[9] = "abegzygj";
char * result = my_union(string1,string2);
printf("%s\n", result);
return 0;
}
Also, do not forget the free the return value of my_union after you done with it.

Reversing String in C for loop error

I have an array of strings and am trying to reverse each string in the array to see if that string is a palindrome. I am using a for loop to increment an int i (the index). However after the I call the reverse function, the value of i becomes some really large number and I cant figure out why this is happening.
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source);
int main() {
const char *strs[] = {
"racecar",
"radar",
"hello",
"world"
};
int i;
char res[] = "";
for (i = 0; i < strlen(*strs); i++) {
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome");
} else {
printf("Not a palindrome");
}
}
return 0;
}
void revString(char *dest, const char *source) {
printf("%s\n", source);
int len = strlen(source);
printf("%d\n", len);
const char *p;
char s;
for (p = (source + (len - 1)); p >= source; p--) {
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
This is the output showing the value of i before and after the revString function is called.
i is 0
i is now 1667588961
Illegal instruction: 4
There are multiple problems in your code:
You pass a destination array char res[] = ""; that is much too small for the strings you want to reverse. It's size is 1. This causes buffer overflow, resulting in undefined behavior.
Use char res[20]; instead.
You enumerate the array of string with an incorrect upper bound. Use this instead:
for (i = 0; i < sizeof(strs) / sizeof(*strs); i++)
The termination test for the loop in revString() is incorrect too: decrementing p when is equal to source has undefined behavior, although it is unlikely to have an consequences. You can simplify this function this way:
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
Here is the resulting code:
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
int main(void) {
const char *strs[] = { "racecar", "radar", "hello", "world" };
char res[20];
for (size_t i = 0; i < sizeof(strs) / sizeof(*strs); i++) {
revString(res, strs[i]);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome\n");
} else {
printf("Not a palindrome\n");
}
}
return 0;
}
Here is Final Code with some change
#include <stdio.h>
#include <string.h>
void revString(char* dest, const char* source);
int main(){
const char* strs[] = {
"racecar",
"radar",
"hello",
"world"
};
static int i;
char res[] = "";
int length = (int) sizeof(strs)/sizeof(char*);
for(i = 0; i < length; i++)
{
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if(strcmp(res, strs[i]) == 0){
printf("Is a palindrome");
}else{
printf("Not a palindrome");
}
}
return 0;
}
void revString(char* dest, const char* source){
printf("%s\n", source);
int len = (int) strlen(source);
printf("%d\n", len);
const char* p;
char s;
for(p = (source + (len - 1)); p >= source; p--){
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
Change 1 :-
int i; to static int i; (Reason:- i is local variable you are calling
function so when function call the value of i will remove and after
that it will assign garbage value.)
change 2 :-
strlen(*strs) to length of array (because strlen(*strs) will give the
length of first string)

Resources