Can't loop through a string for a second time - c

I'm trying to implement the Vigenere Cipher, but I have a problem while trying to loop trough the key. First, all the little functions, although, I don't think the problem is there.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define ALPHANUMERIC "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" /* all alphabetic characters at their corresponding indices */
char* squeeze(char[], int);
char* formatString(char[]);
int findindex(char c);
/* squeeze: remove all occurences of c in s */
char* squeeze(char s[], int c)
{
int i, j;
for (i = j = 0; s[i] != '\0'; i++)
if (s[i] != c)
s[j++] = s[i];
s[j] = '\0';
// printf("%s\n", s);
return s;
}
/* formatString: remove all white spaces and special
characters and convert all letters to upper case */
char* formatString(char input[])
{
int i;
input = squeeze(input, ' ');
for (i = 0; input[i] != '\0'; i++)
{
if (!isalnum(input[i]))
{
input = squeeze(input, input[i]);
--i;
}
if (islower(input[i]))
input[i] = toupper(input[i]);
}
// printf("%s\n", input);
return input;
}
/* findindex: returns the predefined index of a given character */
int findindex(char c)
{
int i;
if (isdigit(c))
return 26 + c - '0';
for (i = 0; ALPHANUMERIC[i] != '\0'; i++)
if (c == ALPHANUMERIC[i])
return i;
return -1;
}
And here is the cipher-function. Just to clarify, my idea was to loop through the text-string in the for-loop and use the j-counter to loop through the codeword by setting it to zero, when it reaches the end of the codeword. All the extra printf-s are for debugging purposes.
void cipher(char codeword[], char text[])
{
int i, j;
char newword[strlen(text)];
codeword = formatString(codeword);
text = formatString(text);
printf("codeword = %s, text = %s\n", codeword, text );
j = -1;
for (i = 0; i < strlen(text); i++)
{
j++;
printf("text[i] = %c, %d, codeword = %c, %d\n", text[i], findindex(text[i]), codeword[i], findindex(codeword[i]));
newword[i] = ALPHANUMERIC[(findindex(text[i]) + findindex(codeword[j])) % 36];
printf("i = %d, j = %d\n", i, j);
if (j == strlen(codeword) - 1)
j = -1;
}
printf("%s\n", newword);
}
So, looking at the code, it all seems fine, until i run it. That's the output with input "ivcho", "ivayloivayloo":
codeword = IVCHO, text = IVAYLOIVAYLOO
text[i] = I, 8, codeword = I, 8
i = 0, j = 0
text[i] = V, 21, codeword = V, 21
i = 1, j = 1
text[i] = A, 0, codeword = C, 2
i = 2, j = 2
text[i] = Y, 24, codeword = H, 7
i = 3, j = 3
text[i] = L, 11, codeword = O, 14
i = 4, j = 4
text[i] = O, 14, codeword = , -1
i = 5, j = 0
text[i] = I, 8, codeword = , -1
i = 6, j = 1
text[i] = V, 21, codeword = , -1
i = 7, j = 2
text[i] = A, 0, codeword = , -1
i = 8, j = 3
text[i] = Y, 24, codeword = G, 6
i = 9, j = 4
text[i] = L, 11, codeword = C, 2
i = 10, j = 0
text[i] = O, 14, codeword = C, 2
i = 11, j = 1
text[i] = O, 14, codeword = :, -1
i = 12, j = 2
QGC5ZW3XHCT9Q
When the counter (j) is set to zero, it just doesn't start over and I have no idea why.

Related

Problem with counting elements in the list of names

I have made one program, where you enter a few characters (10 max). It makes you a list, count average length of surnames, tell about how much different names. But the problem is, when I enter the last number (10) - it sorts me it incorrectly (like 1, 10, 2, 3, 4, 5, 6, 7, 8, 9). Beneath I will present my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct people {
char num[2];
char surname[20];
char name[10];
} peoples[10], c;
int main()
{
int i, j, k = 0, l = 0, m = 0, n = 0;
float s = 0;
char str[100];
system("chcp 1251 > nul");
for (i = 0, j = 0; i < 10; i++, j++)
{
printf("Enter number, surname, name %d of your human: ", i + 1);
gets(str);
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].num[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].surname[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != '\0')
{
peoples[j].name[k] = str[n];
}
else
break;
n++;
k++;
}
n = 0;
k = 0;
}
for (i = 0; i < 10; i++)
{
for (j = i + 1; j < 10; j++)
{
if (!strcmp(peoples[i].name, peoples[j].name))
m = 1;
}
if (m == 0)
l++;
m = 0;
s = s + strlen(peoples[i].surname);
}
for (i = 0; i < 9; i++)
for (j = 0; j < 9; j++)
if (strcmp(peoples[j].num, peoples[j+1].num) > 0)
{
c = peoples[j+1];
peoples[j+1] = peoples[j];
peoples[j] = c;
}
for (i = 0; i < 10; i++)
{
printf("%s ", peoples[i].num);
printf("%s ", peoples[i].name);
printf("%s ", peoples[i].surname);
printf("\n");
}
printf("\nYou have %d different names\n", l);
printf("Avarege lenght of surname is = %f\n", s / 10);
}
If you want to give numeric input, then use actual numeric data.
Change the num field to become an int instead of a single-character string:
struct people {
int num;
char surname[20];
char name[10];
};
Use fgets to read the line:
fgets(str, sizeof str, stdin);
[Error checking left as exercise for reader]
Then use e.g. sscanf for parse your string:
sscanf(str, "%d %s %s", &peoples[j].num, &peoples[j].name, &peoples[j].name);
[Error checking left as exercise for reader]
And finally, instead of doing your own sorting use the standard qsort function:
qsort(peoples, 10, sizeof(struct people), &compare_people_num);
With the comparison function being something like this:
int compare_people_num(const void *a, const void *b)
{
const struct people *p1 = a;
const struct people *p2 = b:
return p1->num - p2->num; // Change order to reverse sort
}
Using sscanf and qsort will make your code much simpler and easier to understand.

Free invalid pointer error in C for Codewars

I am attempting to solve the Codewars problem "Sum Strings as Numbers" in which you are given two strings that are numbers and you need to return a string that is the sum of these numbers. My program works for the first few tests but it breaks down when encountering random tests with strings that are hundreds of digits long. If I use the same exact input on and run the program on my own computer, there are no issues. I get this error from code wars:
Test Crashed
Caught unexpected signal: 6
and this in stderr:
free(): invalid pointer
free(): invalid pointer
this is stdout:
START
Initial variables:
llu_strlen a = 236, llu_strlen(b) = 184
llu_strlen(s1) = 236, llu_strlen(s2) = 236
ret = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
a: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
s1: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
b: 2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
s2: 00000000000000000000000000000000000000000000000000002750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
entering sum loop:
i = 0, digita = 8, digitb = 4, sumstr=12
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
i = 1, digita = 9, digitb = 5, sumstr=15
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052
i = 2, digita = 7, digitb = 6, sumstr=14
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000452
i = 3, digita = 2, digitb = 6, sumstr=09
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009452
i = 4, digita = 6, digitb = 2, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 5, digita = 3, digitb = 7, sumstr=10
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 6, digita = 9, digitb = 9, sumstr=19
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009089452
i = 7, digita = 9, digitb = 8, sumstr=18
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089089452
i = 8, digita = 3, digitb = 4, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000889089452
i = 9, digita = 7, digitb = 0, sumstr=07
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007889089452
i = 10, digita = 0, digitb = 5, sumstr=05
(continues on like that for a while)
000000000000000000000000000121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 210, digita = 7, digitb = 0, sumstr=07
000000000000000000000000007121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 211, digita = 2, digitb = 0, sumstr=02
000000000000000000000000027121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 212, digita = 8, digitb = 0, sumstr=08
000000000000000000000000827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 213, digita = 4, digitb = 0, sumstr=04
000000000000000000000004827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 214, digita = 6, digitb = 0, sumstr=06
000000000000000000000064827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 215, digita = 9, digitb = 0, sumstr=09
000000000000000000000964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 216, digita = 1, digitb = 0, sumstr=01
000000000000000000001964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 217, digita = 2, digitb = 0, sumstr=02
000000000000000000021964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 218, digita = 7, digitb = 0, sumstr=07
000000000000000000721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 219, digita = 5, digitb = 0, sumstr=05
000000000000000005721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 220, digita = 1, digitb = 0, sumstr=01
000000000000000015721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 221, digita = 9, digitb = 0, sumstr=09
000000000000000915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 222, digita = 6, digitb = 0, sumstr=06
000000000000006915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 223, digita = 4, digitb = 0, sumstr=04
000000000000046915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 224, digita = 9, digitb = 0, sumstr=09
000000000000946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 225, digita = 3, digitb = 0, sumstr=03
000000000003946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 226, digita = 4, digitb = 0, sumstr=04
000000000043946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 227, digita = 4, digitb = 0, sumstr=04
000000000443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 228, digita = 4, digitb = 0, sumstr=04
000000004443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 229, digita
here is the program that I run on code wars which throws an error:
#include <malloc.h>
#include <string.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
and here is the program I run on my computer which finds the result successfully:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
int main(void)
{
char * res;
res = strsum("78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798",
"2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654");
return 0;
}
The error always occurs while the print statement in the sum for loop is printing. The amount of stuff that print statement manages to print out before being cut off changes every time the program is run. This test has random strings of numbers as input, so the input changes each time. The error usually occurs when i approaches maxlen, but i can sometimes be 30-40 less than maxlen.
In your function you allocate ret in this line:
ret = (char *) malloc((maxlen+2) * sizeof(char));
you then return ret at the end of your function, presumably to be freed by the caller.
However within your function you also have these lines:
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
This means that the the ret you are returning no longer has the same pointer value as the one you received from malloc. Then when you call free in the caller the free function doesn't know what the pointer is.
One way to fix this is to find a different way to remove leading zeros, one that doesn't change the value of ret.
These don't have room for the null terminator:
char s1[maxlen], s2[maxlen];
which makes your program write out of bounds and have undefined behavior, so make them:
char s1[maxlen+1], s2[maxlen+1];
And here you change ret, making it impossible for a user to free the malloced memory:
while (*ret == '0' && *(ret+1) != '\0')
ret++;
instead, move the part of the string that you want to keep:
char *tmp = ret;
while (*tmp == '0' && tmp[1] != '\0') tmp++;
memmove(ret, tmp, maxlen-(tmp-ret)+2);
Another detail: You declare ret as static which only makes it unsafe to use the function in a multithreaded program. It does not provide any benefits at all. Just make it:
char *ret;
Another possible improvement would be to not allocate s1 and s2 at all, but to read directly from a and b and to skip leading zeroes before doing the calculation. Example:
#define SWAP(type, x, y) \
do { \
type tmp = x; \
x = y; \
y = tmp; \
} while (0)
char *strsum(const char *a, const char *b) {
while(*a == '0' && a[1] != '\0') ++a; // skip leading zeroes
while(*b == '0' && b[1] != '\0') ++b; // skip leading zeroes
size_t lena = strlen(a);
size_t lenb = strlen(b);
if (lena == 0 || lenb == 0) return NULL;
if (lena < lenb) { // make `a` the longest string
SWAP(const char *, a, b);
SWAP(size_t, lena, lenb);
}
char *ret = malloc(lena + 2); // may add one digit + null terminator
ret[lena + 1] = '\0'; // null terminate the result
int carry = 0;
size_t i = 1;
// loop while both `b` and `a` have digits:
for (; i <= lenb; ++i) {
int sum = carry + (a[lena - i] - '0') + (b[lenb - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// loop while only `a` has digits:
for (; i <= lena; ++i) {
int sum = carry + (a[lena - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// if no carry, move everything one step to the left:
if (carry == 0) memmove(ret, ret + 1, lena + 2 - 1);
else ret[0] = carry + '0'; // carry goes to the first position
return ret;
}
Demo

How can I convert this method to become recursive?

Method checks for the amount of each character and if its even for every character, it returns 1. Otherwise, it returns 0. String is passed via str[]. chars[] has its every value set to one at the start. It's hard to picture this becoming recursive, any help on teaching is appreciated.
int recursionCheckEven(int i, int j, char str[], int chars[20]) {
for (i = 0; i < strlen(str); i+=2) {
int count = 0;
for (j = i; j < strlen(str); j+=2) {
if (str[i] == str[j] && chars[j] == 1) {
count++;
chars[i] = 2;
chars[j] = 2;
}
}
if (count % 2 != 0) {
chars[i] = 0;
}
}
for (int k = 0; k < 20; k++) {
if (chars[k] == 0) {
return 0;
break;
}
}
return 1;
}
How I call this:
for (unsigned int i = 0; i < stringcount; i++) {
int chars[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
if(recursionCheckEven(0, 0, strings[i], chars)) {
printf("The %dth string has even number of characters\n", i);
}
}
You can use a loop to go through the characters in a non-recursive way (this is recommended). The idea of recursion is to avoid using a loop (which is actually not recommended and wastes stack memory and causes other problems).
For recursive check, you can use pointers the check each element, then go to the next element and use the same function.
To help you get started, this is a recursive function which takes a string and counts the number of each character.
int recursive(int total, char* ptr, char ch)
{
if (*ptr == '\0')
return total;
if (*ptr == ch)
total++;
return recursive(total, ptr + 1, ch);
}
int main(void)
{
char *str = "111";
char ch = '1';
int total = recursive(0, str, ch);
printf("total of char %c in %s: %d\n", ch, str, total);
return 0;
}

How to avoid duplicates when finding all k-length substrings

I want to display all substrings with k letters, one per line, but avoid duplicate substrings. I managed to write to a new string all the k length words with this code:
void subSent(char str[], int k) {
int MaxLe, i, j, h, z = 0, Length, count;
char stOu[1000] = {'\0'};
Length = (int)strlen(str);
MaxLe = maxWordLength(str);
if((k >= 1) && (k <= MaxLe)) {
for(i = 0; i < Length; i++) {
if((int)str[i] == 32) {
j = i = i + 1;
} else {
j = i;
}
for(; (j < i + k) && (Length - i) >= k; j++) {
if((int)str[j] != 32) {
stOu[z] = str[j];
} else {
stOu[z] = str[j + 1];
}
z++;
}
stOu[z] = '\n';
z++;
}
}
}
But I'm struggling with the part that needs to save only one time of a word.
For example, the string HAVE A NICE DAY
and k = 1 it should print:
H
A
V
E
N
I
C
D
Y
Your subSent() routine poses a couple of challenges: first, it neither returns nor prints it's result -- you can only see it in the debugger; second it calls maxWordLength() which you didn't supply.
Although avoiding duplicates can be complicated, in the case of your algorithm, it's not hard to do. Since all your words are fixed length, we can walk the output string with the new word, k letters (plus a newline) at a time, doing strncmp(). In this case the new word is the last word added so we quit when the pointers meet.
I've reworked your code below and added a duplication elimination routine. I didn't know what maxWordLength() does so I just aliased it to strlen() to get things running:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define maxWordLength strlen
// does the last (fixed size) word in string appear previously in string
bool isDuplicate(const char *string, const char *substring, size_t n) {
for (const char *pointer = string; pointer != substring; pointer += (n + 1)) {
if (strncmp(pointer, substring, n) == 0) {
return true;
}
}
return false;
}
void subSent(const char *string, int k, char *output) {
int z = 0;
size_t length = strlen(string);
int maxLength = maxWordLength(string);
if (k >= 1 && k <= maxLength) {
for (int i = 0; i < length - k + 1; i++) {
int start = z; // where does the newly added word begin
for (int j = i; (z - start) < k; j++) {
output[z++] = string[j];
while (string[j + 1] == ' ') {
j++; // assumes leading spaces already dealt with
}
}
output[z++] = '\n';
if (isDuplicate(output, output + start, k)) {
z -= k + 1; // last word added was a duplicate so back it out
}
while (string[i + 1] == ' ') {
i++; // assumes original string doesn't begin with a space
}
}
}
output[z] = '\0'; // properly terminate the string
}
int main() {
char result[1024];
subSent("HAVE A NICE DAY", 1, result);
printf("%s", result);
return 0;
}
I somewhat cleaned up your space avoidance logic but it can be tripped by leading spaces on the input string.
OUTPUT
subSent("HAVE A NICE DAY", 1, result);
H
A
V
E
N
I
C
D
Y
subSent("HAVE A NICE DAY", 2, result);
HA
AV
VE
EA
AN
NI
IC
CE
ED
DA
AY
subSent("HAVE A NICE DAY", 3, result);
HAV
AVE
VEA
EAN
ANI
NIC
ICE
CED
EDA
DAY

i am getting error in this c program

i am trying to implement this c program , i want to expand strings
eg a-z to a b c d ...z etc
when i put the input string as a-z i dont get the o/p but when i use the input string as az or without using the - i get the desired o/p
#include<stdio.h>
main()
{
char s1[20] = "a z", s2[10], s3[30];
int k = 0, i = 0;
while (s1[i] != '\0')
{
if((s1[i] >= 65 && s1[i]<= 90) || (s1[i] >= 97 && s1[i]<= 122))
s2[k]=s1[i];
i++; k++;
}
s2[k] = '\0';
for (int m = s2[0] ; m <= s2[1] ; m++)
printf("%c ",m);
}
You should only update 'k' position when required:
if((s1[i] >= 65 && s1[i]<= 90) || (s1[i] >= 97 && s1[i]<= 122)) {
s2[k]=s1[i];
k++;
}
i++;
Furthermore your destination array s2 (the one in which you store the expanded letters) shall be of at least 27 size (26+\0).
as per your need:
char s1[20] = "a-z", s2[10],s3[30]; //a-z are now 3 characters
for(int m=s2[0]; m<=s2[2] ; m++) //loop for 3rd character i.e. "z".
printf("%c ",m);
output : a b c d e f g h i j k l m n o p q r s t u v w x y z
Why bother so much? This small piece of code would do what you need:
#include<stdio.h>
int main()
{
char s1[4] = "a-z";
int m;
for(m=s1[0]; m<=s1[2]; m++)
{
printf("%c ",m);
}
return 0;
}
#include <stdio.h>
char *expand(char *out, const char *in){
size_t i, j;
for(j = i = 0; in[i] != '\0'; ++i){
if(in[i] != '-' || i == 0 || in[i+1] == '\0' || (unsigned char)in[i-1] >= (unsigned char)in[i+1]){
out[j++] = in[i];
} else {
unsigned char ch_s = in[i-1] + 1, ch_e = in[i+1];
while(ch_s < ch_e){
out[j++] = ch_s++;
}
}
}
out[j] = '\0';
return out;
}
int main(void){
const char *test[] = {
"a-z", "-a-e", "A-Z0-9", "a-a", "z-a", "a-e-g", "this is test-print"
};
char expanded[128];
size_t i, size = sizeof(test)/sizeof(*test);
for(i = 0; i < size; ++i){
printf("%s expand to %s\n", test[i], expand(expanded, test[i]));
}
return 0;
}
#if 0
a-z expand to abcdefghijklmnopqrstuvwxyz
-a-e expand to -abcde
A-Z0-9 expand to ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
a-a expand to a-a
z-a expand to z-a
a-e-g expand to abcdefg
--/ expand to -./
test-print expand to test-print
#endif

Resources