Finding Substring in 2D Array(Puzzle) - c

I have been trying to make a word puzzle(without using any library functions)like you would find in a newspaper like the following:
15 rows 12 colums
X T Z M Q Y K C E C F H -->12 chars
S H O U T E X O E A P I
X G T L Q B E L T N F K
'
'
'
as you can see in the second row there is the word SHOUT. Now the puzzle is designed so that the user can input any sort of char set they want line by line.
What I want to do is when a word is searched (like SHOUT) I would return its starting index. The index I imagined will start at 0 and end at 180, as 12*15=180 like this to be clear:
X T Z M Q Y K C E C F H
0 1 2 3 4 5 6 7 8 9 10 11
S H O U T E X O E A P I
12 13 14 15 16 17 18 19 20 21 22 23
'
'
'
'''''''''''''''''''179
Its hard to explain it without a picture, I hope you understand.
Now the tricky thing is words can be in every direction (up to down, down to up, left to right, right to left). I have written most of the code but keep getting errors and it only can check if the word exists from left to right.
#include <stdio.h>
#define COLUNM 12
#define ROW 15
int computeLength (char str[50]) {
int i;
for (i = 0; str[i] != '\0'; ++i) {
}
return i;
}
int findString(char matrix[ROW][COLUNM], char string[], int length) {
int i = 0, j, k = 0, searchlenght = 0;
length = computeLength(string);
for (j = 0; j < ROW; j++) {
if (matrix[j][k] == string[k]) {
searchlenght++;
}
}
i++;
if (searchlength == length) {
return i;
}
}
int main() {
int i, j = 0;
char matrix[ROW][COLUNM];
char string[50];
int b = 1;
for (i = 0; i < ROW; i++) {
printf("Enter line %d of the puzzle :\n", i + 1);
scanf("%s", &matrix[j][i]);
j++;
}
while (b > 0) {
printf("Enter the string to be searched in the puzzle:\n");
scanf("%s", &string[50]);
if ((string[0] != 'q') || (string[0] != 'Q')) {
b = 0;
}
}
return 0;
}
I don't think this is so hard to implement with python but I'm so unfamiliar with C that I keep getting errors and warnings.
Only part that needs work is findString function. Don't bother with input as I will test it myself.
Could you please help?
**The only part that does not work is length=computeLength(str1); thşs when I enter computeLength("Shout") it returns 5 but in this piece of code it returns 2 which messes up the result **
int findString(char matrix[ROW][COLUNM],char str1[],int length){
int i,j,wordcounting;
int true=1;
length=computeLength(str1);
printf("%d",length);
for(j=0;j<ROW;j++){
if(matrix[i][j]==str1[0]){
for(wordcounting=1;wordcounting<length;wordcounting++){
if((matrix[i][j+wordcounting]!=str1[wordcounting])){
true=0;
break;
}
}
}
i++;}
if(true==1){return (i-length);}
}
When I say printf("%d",computeLength(string)); even before ı input a string it becomes 2

Here is a loooooooog answer where I explain the more I can your problems, how to solve them, and finally how to implement the search step by step up to a final solution.
Have a good reading !
There a lot of problems in your code, first it cannot be compiled.
The line 29 is invalid, replace
int findString(char matrix[ROW][COLUNM],char string[15],int computeLength(string[15])){
by
int findString(char matrix[ROW][COLUNM], char string[15])
Note also the size 15 is useless you can use char string[] or char * string for the parameter string
The line 39 is invalid, replace
if(count==computeLength(string[15])){
by
if(count==computeLength(string)){
Now you can compile your program, but this not enough.
Some problems in main.
You exchanged the indexes in the line
scanf("%s",&matrix[j][i]);
It can be replaced by
scanf("%s",&matrix[i][0]);
(I used 0 rather than j because it is more clear, that does not ask us to check j values 0)
But this is not enough, scanf can read more than COLUNM characters if the input is invalid, and even the input is 12 characters as you expect you forget scanf will also write the null character finishing the string, so it writes 13 characters.
A way is to read in string which is longer than COLUMN more 2 and check the length of the input string. So your for can be replaced by :
for(i = 0 ; i < ROW ; i++)
{
printf("Enter line %d of the puzzle :\n",i+1);
if ((scanf("%49s", string) != 1) ||
(strlen(string) != COLUMN)) {
puts("invalid line");
return -1;
}
memcpy(&matrix[i][0], string, COLUMN);
i++;
}
Note also at the end i is incremented rather than j.
In the while loop
scanf("%s",&string[50]);
is invalid because it will place the result after string, the index must be 0 and in fact you can just give string.
As before if the input as more than 49 characters scanf will write out of string, so do
scanf("%49s", string);
If you want to allow to search a string of 50 characters without counting the final null character you have to size it with 51 and replace 49 by 50.
Out of printing and reading the while loop does nothing, it is very probable you wanted to call findString in it and to write the returned value, until the first read character is q or Q. For instance :
for (;;) {
puts("Enter the string to be searched in the puzzle:");
if ((scanf("%49s", string) != 1) || (string[0] =='q') || (string[0] == 'Q'))
break;
printf("position in the puzzle: %d\n", findString(matrix, string));
}
At the end of main the interest of that line is obscure :
printf("%d",computeLength("küfür"));
In printPuzzle you missed to introduce a newline after you print PUZZLE, you can just replace printf by puts. Note it is useless to ask printf to search for % etc while you know there is none.
In findString
A first problem is you only return a value if count==computeLength(string) is true, you need to always to return a value. Typically you can return -1 if the string is not in the puzzle, so
return (count==computeLength(string)) ? i : -1;
but this is wrong too, and for two reasons :
when you reach the test i always value 180, not the position where the string was
this is not because count==computeLength(string) is true that the string was found because of the way you used to increment count and the next error :
You do not search correctly the string in the puzzle because your first loop on i goes though the string (string[i]), and worst will access to 180 characters in it while its length is only 49 (without the final null character). You also do not stop to search even you find the string. And in your algorithm you forget the characters of string must be placed consecutively in the matrix, you each time you (wrongly) find a character of the string anywhere in the matrix you increment count.
Just considering you search the string horizontally from left to right :
The loop on string must be the more embedded loop to check its characters are consecutive in the matrix.
You have one loop on the row an one on the column, this is useless and just make the job complex for nothing. Because matrix is an array the character at matrix[r][COLUMN] is the character at matrix[r+1][0], that means you can go through matrix like it is a string of ROW*COLUMN characters.
I let you rewrite findString, it is like strstr except you return the index or -1 rather than the address of the substring or NULL
[edit with proposal for the search functions]
To explain I will use that small matrix more easy to look at :
#define COLUMN 3
#define ROW 5
char Matrix[ROW][COLUMN] = { { 'a', 'b' , 'c' },
{ 'd', 'e' , 'f' },
{ 'g', 'h' , 'i' },
{ 'j', 'k' , 'l' },
{ 'm', 'n' , 'o' } };
Let start with searching from left to right, this is similar to the classic strstr function except the return value and there is a rollback at the end of the matrix. Let decide the value is -1 if the string is not found else the position of its first character times 1000 more the position of its last character. The definition can be :
int search_left2right(char * matrix, char * word)
{
int i;
for (i = 0; i != ROW*COLUMN; ++i) {
int j = i;
char * w = word;
while (*w == matrix[j]) {
if (!*++w)
return i * 1000 + j;
if (++j == ROW*COLUMN)
j = 0;
}
}
return -1;
}
Compilation and execution with that main :
int main()
{
printf("%d\n", search_left2right((char *) Matrix, "cde"));
printf("%d\n", search_left2right((char *) Matrix, "noa"));
printf("%d\n", search_left2right((char *) Matrix, "cdf"));
return 0;
}
pi#raspberrypi:/tmp $ ./a.out
2004
13000
-1
pi#raspberrypi:/tmp $
2004 if for 2 and 4, 13000 if for 13 and 0, the string is not found in the last case, this is ok
Searching from right to left.
A first obvious way is to reuse the previous function and to reverse the string before to search it. In case the string is found in the result the position of the first and last characters are just reversed too.
An other way is to iterate on the string to search in the reverse order, let choose that way.
Searching from right to left or from left to right.
To indicate the direction the parameter wstep is added and values 1 for left to right, else -1. The definition can be :
/* manual strlen, you want to define all string functions */
int strLen(char * s)
{
char * p = s;
while (*p)
p += 1;
return p - s;
}
int search_horiz(char * matrix, char * word, int wstep)
{
int i;
int wbegin = (wstep == 1) ? 0 : strLen(word) - 1;
int wend = (wstep == 1) ? strLen(word) - 1 : 0;
for (i = 0; i != ROW*COLUMN; ++i) {
int j = i;
int k = wbegin;
while (word[k] == matrix[j]) {
if (k == wend)
return (wstep == 1) ? i * 1000 + j : j * 1000 + i;
k += wstep;
if (++j == ROW*COLUMN)
j = 0;
}
}
return -1;
}
Compilation and execution with that main :
int main()
{
printf("%d\n", search_horiz((char *) Matrix, "cde", 1));
printf("%d\n", search_horiz((char *) Matrix, "edc", -1));
printf("%d\n", search_horiz((char *) Matrix, "noa", 1));
printf("%d\n", search_horiz((char *) Matrix, "aon", -1));
printf("%d\n", search_horiz((char *) Matrix, "cdf", 1));
printf("%d\n", search_horiz((char *) Matrix, "fdc", -1));
return 0;
}
pi#raspberrypi:/tmp $ gcc -g -Wall m.c
pi#raspberrypi:/tmp $ ./a.out
2004
4002
13000
13
-1
-1
pi#raspberrypi:/tmp $
Searching from top to bottom.
When we search from left to right we compare the characters from to string with the consecutive characters in the matrix (step is 1), more the roll back.
To search from top to bottom we do not have to look consecutive characters in the matrix, we want to stay in the same vertical so the step is COLUMN. Of course this is not the case when we are on the last line, in that case we go back on the first line and move to the right, except from the last character of the matrix where we have to rollback to the first character. The definition can be :
int search_top2down(char * matrix, char * word)
{
int i;
for (i = 0; i != ROW*COLUMN; ++i) {
int j = i;
char * w = word;
while (*w == matrix[j]) {
if (!*++w)
return i * 1000 + j;
if ((j += COLUMN) >= ROW*COLUMN)
j = (j - ROW*COLUMN + 1) % COLUMN;
}
}
return -1;
}
Compilation and execution with that main :
int main()
{
printf("%d\n", search_top2down((char *) Matrix, "dgj"));
printf("%d\n", search_top2down((char *) Matrix, "knc"));
printf("%d\n", search_top2down((char *) Matrix, "oad"));
return 0;
}
pi#raspberrypi:/tmp $ gcc -g -Wall m.c
pi#raspberrypi:/tmp $ ./a.out
3009
10002
14003
pi#raspberrypi:/tmp $
Searching from left to right or from top to bottom
But comparing search_left2right and search_top2down we can see they have almost the same definition, the only change is the value of the step in the matrix and the correction when the step cannot be applied alone. So it is possible to have:
int search_left2right_top2down(char * matrix, char * word, int step, int correct)
{
int i;
for (i = 0; i != ROW*COLUMN; ++i) {
int j = i;
char * w = word;
while (*w == matrix[j]) {
if (!*++w)
return i*100 + j;
if ((j += step) >= ROW*COLUMN)
j = (j - ROW*COLUMN + correct) % COLUMN;
}
}
return -1;
}
To do left to right step is 1 and correct is 0, to do top to bottom step is COLUMN and correct is 1.
Searching in all the four directions
The needed modification to search from bottom to top from top to bottom are like it was to search right to left from left to right.
That means we can have easily only one search function managing left to right, right to left, top to bottom and bottom to top. For instance :
int search(char * matrix, char * word, int wstep, int step, int correct)
{
int i;
int wbegin = (wstep == 1) ? 0 : strLen(word) - 1;
int wend = (wstep == 1) ? strLen(word) - 1 : 0;
for (i = 0; i != ROW*COLUMN; ++i) {
int j = i;
int k = wbegin;
while (word[k] == matrix[j]) {
if (k == wend)
return (wstep == 1) ? i * 1000 + j : j * 1000 + i;
k += wstep;
if ((j += step) >= ROW*COLUMN)
j = (j - ROW*COLUMN + correct) % COLUMN;
}
}
return -1;
}
With that main compilation and execution :
int main()
{
printf("%d\n", search((char *) Matrix, "cde", 1, 1, 0));
printf("%d\n", search((char *) Matrix, "noa", 1, 1, 0));
printf("%d\n", search((char *) Matrix, "cdf", 1, 1, 0));
putchar('\n');
printf("%d\n", search((char *) Matrix, "edc", -1, 1, 0));
printf("%d\n", search((char *) Matrix, "aon", -1, 1, 0));
printf("%d\n", search((char *) Matrix, "fdc", -1, 1, 0));
putchar('\n');
printf("%d\n", search((char *) Matrix, "dgj", 1, COLUMN, 1));
printf("%d\n", search((char *) Matrix, "knc", 1, COLUMN, 1));
printf("%d\n", search((char *) Matrix, "oad", 1, COLUMN, 1));
putchar('\n');
printf("%d\n", search((char *) Matrix, "jgd", -1, COLUMN, 1));
printf("%d\n", search((char *) Matrix, "cnk", -1, COLUMN, 1));
printf("%d\n", search((char *) Matrix, "dao", -1, COLUMN, 1));
return 0;
}
pi#raspberrypi:/tmp $ gcc -Wall m.c
pi#raspberrypi:/tmp $ ./a.out
2004
13000
-1
4002
13
-1
3009
10002
14003
9003
2010
3014
pi#raspberrypi:/tmp $
Let notice to give the 3 parameters to indicate how to process is not a pretty way, I used them because I considered it was better to have them to explain, but because there are always the same it is easy to improve :
#include <stdio.h>
#define COLUMN 3
#define ROW 5
/* manual strlen, you want to define all string functions */
int strLen(const char * s)
{
const char * p = s;
while (*p)
p += 1;
return p - s;
}
typedef struct SearchParameters {
int wstep;
int step;
int correct;
} SearchParameters;
const SearchParameters Left2Right = { 1, 1, 0 };
const SearchParameters Right2Left = { -1, 1, 0 };
const SearchParameters Top2Bottom = { 1, COLUMN, 1 };
const SearchParameters Bottom2Top = { -1, COLUMN, 1 };
int search(const char * matrix, const char * word, SearchParameters how)
{
int i;
int wbegin = (how.wstep == 1) ? 0 : strLen(word) - 1;
int wend = (how.wstep == 1) ? strLen(word) - 1 : 0;
for (i = 0; i != ROW*COLUMN; ++i) {
int j = i;
int k = wbegin;
while (word[k] == matrix[j]) {
if (k == wend)
return (how.wstep == 1) ? i * 1000 + j : j * 1000 + i;
k += how.wstep;
if ((j += how.step) >= ROW*COLUMN)
j = (j - ROW*COLUMN + how.correct) % COLUMN;
}
}
return -1;
}
/* */
typedef struct TestCase {
const char * str;
const SearchParameters * how;
const char * strHow;
} TestCase;
void test(const char (*m)[3], const TestCase * tc)
{
int r = search((char *) m, tc->str, *(tc->how));
if (r == -1)
printf("cannot found '%s' in '%s'\n", tc->str, tc->strHow);
else
printf("'%s' found in '%s', start at %d, end at %d\n",
tc->str, tc->strHow, r / 1000, r % 1000);
}
int main()
{
static const char matrix[ROW][COLUMN] = { { 'a', 'b' , 'c' },
{ 'd', 'e' , 'f' },
{ 'g', 'h' , 'i' },
{ 'j', 'k' , 'l' },
{ 'm', 'n' , 'o' } };
static const TestCase tests[] = {
{ "cde", &Left2Right, "Left2Right" },
{ "noa", &Left2Right, "Left2Right" },
{ "cdf", &Left2Right, "Left2Right" },
{ "edc", &Right2Left, "Right2Left" },
{ "aon", &Right2Left, "Right2Left" },
{ "fdc", &Right2Left, "Right2Left" },
{ "dgj", &Top2Bottom, "Top2Bottom" },
{ "knc", &Top2Bottom, "Top2Bottom" },
{ "oad", &Top2Bottom, "Top2Bottom" },
{ "jgd", &Bottom2Top, "Bottom2Top" },
{ "cnk", &Bottom2Top, "Bottom2Top" },
{ "dao", &Bottom2Top, "Bottom2Top" }
};
int t;
for (t = 0; t != sizeof(tests) / sizeof(TestCase); t += 1)
test(matrix, &tests[t]);
return 0;
}
Compilation and execution:
pi#raspberrypi:/tmp $ gcc -Wall mm.c
pi#raspberrypi:/tmp $ ./a.out
'cde' found in 'Left2Right', start at 2, end at 4
'noa' found in 'Left2Right', start at 13, end at 0
cannot found 'cdf' in 'Left2Right'
'edc' found in 'Right2Left', start at 4, end at 2
'aon' found in 'Right2Left', start at 0, end at 13
cannot found 'fdc' in 'Right2Left'
'dgj' found in 'Top2Bottom', start at 3, end at 9
'knc' found in 'Top2Bottom', start at 10, end at 2
'oad' found in 'Top2Bottom', start at 14, end at 3
'jgd' found in 'Bottom2Top', start at 9, end at 3
'cnk' found in 'Bottom2Top', start at 2, end at 10
'dao' found in 'Bottom2Top', start at 3, end at 14
pi#raspberrypi:/tmp $

Just looking at the compile error mentioned (and only the compile error), I suggest you do something like this:
int findString(char matrix[ROW][COLUNM],char string[15])
{
int length = computeLength(string);
...
}
You can't have the way you declared the function like what you did. Now slight further recommendation...
There is already a C function that can compute C string lengths:
#include <string.h>
...
const char* string = "hello";
int length = strlen(string);
...

Related

Is it possible to simplify this algorithm so that it only uses 1 loop and 2 variables?

Is it possible to get the same results as this code using only a and b?
I'm trying to calculate c from a and b to avoid using a third variable, but I can't find a solution.
#include <stdio.h>
#include <stdlib.h>
const int LENGTH = 20;
int main()
{
char arr[LENGTH];
for (int a = 0, b = 1, c = 0; c < LENGTH; c++) {
if (a < b) {
arr[c] = '*';
a++;
} else {
arr[c] = ' ';
a = 0;
b++;
}
}
printf(arr);
return EXIT_SUCCESS;
}
Code result : * ** *** **** *****
In the event that checking if a number is triangular by linking or writing some sort of sqrt() function is not a solution that you find acceptable:
Each group of **... in the final string has a ' ' at the end, so the shortest segment in the string is "* ", which is 2 chars long.
The c in your loop is the index of the char array that this iteration should write to, the a is the index inside the current group of '*'s, and b is length of the current group of '*'s less one (since we want to count the spaces). Directly before the if clause in your for loop, it can be said that c is the sum from 2 to b plus a.
In other words, if a=0, and b=1, then c=0, because the sum from 2 to 0 is 0, plus 0 is 0.
If a=3, and b=4, then c= (2+3+4) + 3 = 12.
This means that you could write your code like this:
#include <stdio.h>
const int LENGTH = 20;
int sumFromTwo(int in){ //Recursive function to calculate sigma(2:in)
if(in < 2)
return 0;
else
return in + sumFromTwo(in - 1);
}
int main()
{
char arr[LENGTH + 1]; //Extra byte for null-terminator
for (int a = 0, b = 1; sumFromTwo(b) + a < LENGTH ; ) {
if (a < b) {
arr[sumFromTwo(b) + a] = '*';
a++;
} else {
arr[sumFromTwo(b) + a] = ' ';
a = 0;
b++;
}
}
arr[LENGTH] = '\0'; //Always null-terminate your strings
printf(arr);
return EXIT_SUCCESS;
}
But using recursion to avoid using a variable that is almost certainly going to be optimized into a register anyway is not going to save your computer any resources, least of all RAM, so it is definitely cleaner to do it the way you did in your question (but please null-terminate your string before passing it to your choice of printf or puts).

Why I am getting a space character in my program in the place of third last character?

Why I am getting a space character in my program in the place of third last character?
Even if I change the string str variable I get the same result.
#include <stdio.h>
#include <string.h>
void parser(char array[])
{
int a, b;
for (int i = 0; i < strlen(array); i++) {
if (array[i] == '>') {
a = i;
break;
}
}
for (int j = a; j < strlen(array); j++) {
if (array[j] == '<') {
b = j;
}
}
for (int p = 0, q = a + 1; p < b - a - 1, q < b; p++, q++) {
array[p] = array[q];
array[b - a] = '\0';
printf("%c", array[p]);
}
}
int main()
{
char str[] = "<h1>hello there i am programmer.</h1>";
parser(str);
return 0;
}
There are many things that could be written better in the code but they do not affect the result.
The line that produces the unexpected outcome is:
array[b-a]='\0';
When this for loop starts...
for(int p=0,q=a+1;p<b-a-1,q<b;p++,q++){
array[p]=array[q];
array[b-a]='\0';
printf("%c",array[p]);
}
... the values of a and b are 3 and 32.
The statement array[b-a]='\0'; puts the NUL terminator character at position 29 in array.
The loop starts with p=0, q=4 (a+1) and repeats until p reaches 28 and q reaches 31 (q<b)*.
When p is 25, q is 29 and array[29] has been repeatedly set to '\0' on the previous iterations, therefore '\0' is copied at position 25 and printed on screen.
You should set the NUL terminator only once, after the loop. And the right position for it is b-a-1, not b-a; you expressed this correctly in the for initialization (p=0) and exit condition (p<b-a-1).
All in all, the code around the last for loop should be like this:
for(int p=0, q=a+1;q<b;p++,q++){
array[p]=array[q];
printf("%c",array[p]);
}
array[b-a-1]='\0';
*The condition p<b-a-1 is ignore because of the comma character. You probably want & between the conditions but they are equivalent, one of them is enough.

function doesn't pass certain test case

I have a problem with one of the test for my solution for challenge in codewars. I have to write a function that returns alphabet position of characters in input string. My solution is below. I pass all my test and also tests from codewars but fail on this one (I did not implement this test code it was pat of the test code implemented by code wars):
Test(number_tests, should_pass) {
srand(time(NULL));
char in[11] = {0};
char *ptr;
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 10; j++) {
char c = rand() % 10;
in[j] = c + '0';
}
ptr = alphabet_position(in);
cr_assert_eq(strcmp(ptr, ""), 0);
free(ptr);
}
}
The error I receive is following: The expression (strcmp(ptr, "")) == (0) is false. Thanks for the help!
p.s Also I noticed that I am leaking memory (I don't know how to solve this so I suppose I would use array to keep track of string and don't use malloc) --> I suppose this is not an issue I would just free(ptr) in main function.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *alphabet_position(char *text);
// test
int main()
{
if (!strcmp("1 2 3", alphabet_position("abc")))
{
printf("success...\n");
}
else
{
printf("fail...\n");
}
if (!strcmp("", alphabet_position("..")))
{
printf("success...\n");
}
else
{
printf("fail...\n");
}
if (!strcmp("20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11", alphabet_position("The sunset sets at twelve o' clock.")))
{
printf("success...\n");
}
else
{
printf("fail...\n");
}
}
char *alphabet_position(char *text)
{
// signature: string -> string
// purpose: extact alphabet position of letters in input string and
// return string of alphabet positions
// return "123"; // stub
// track numerical value of each letter according to it's alphabet position
char *alph = "abcdefghijklmnopqrstuvwxyz";
// allocate maximum possible space for return string
// each char maps to two digit number + trailing space after number
char *s = malloc(sizeof(char) * (3 * strlen(text) + 1));
// keep track of the begining of return string
char *head = s;
int index = 0;
int flag = 0;
while(*text != '\0')
{
if ( ((*text > 64) && (*text < 91)) || ((*text > 96) && (*text < 123)))
{
flag = 1;
index = (int)(strchr(alph, tolower(*text)) - alph) + 1;
if (index > 9)
{
int n = index / 10;
int m = index % 10;
*s = n + '0';
s++;
*s = m + '0';
s++;
*s = ' ';
s++;
}
else
{
*s = index + '0';
s++;
*s = ' ';
s++;
}
}
text++;
}
if (flag != 0) // if string contains at least one letter
{
*(s -1) = '\0'; // remove the trailing space and insert string termination
}
return head;
}
Here is what I think is happening:
In the cases where none of the characters in the input string is an alphabet character, s is never used, and therefore the memory allocated by malloc() could be anything. malloc() does not clear / zero-out memory.
The fact that your input case of ".." passes is just coincidence. The codewars test case does many such non-alphabetical tests in a row, each of which causes a malloc(), and if any one of them fails, the whole thing fails.
I tried recreating this situation, but it's (as I say) unpredictable. To test this, add a debugging line to output the value of s when flag is still 0:
if (flag != 0) { // if string contains at least one letter
*(s -1) = '\0'; // remove the trailing space and insert string termination
}
else {
printf("flag is still 0 : %s\n", s);
}
I'll wager that sometimes you get a garbage / random string that is not "".

N permutations of string (with repetitions)

I have to print first n permutations with repetitions of a string.
String is formed with characters 'a','b','c','d','e','f'.
For example, first 10 permutations would be: aaaaaa,aaaaab,aaaaac,aaaaad,aaaaae,aaaaaf,aaaaba,aaaabb,aaaabc,aaaabd.
This is my failed attempt:
int main()
{
FILE *c;
c = fopen("C:\\Users\\Korisnik\\Desktop\\tekst\\permutacija.txt", "w");
char s[6] = "abcdef";
char t[6] = "aaaaaa";
s[6] = '\0';
t[6] = '\0';
int k = strlen(t);
int m = k;
int n;
scanf("%d", &n);
int br = 0;
int i = 0;
while (br < n) {
i = 0;
while (i < 6) {
t[k-1] = s[i];
fprintf(c, "%s ", t);
fprintf(c, "\n");
i++;
br++;
if (br == n) {
exit(1);
}
}
t[k-1] = 'a';
k--;
if (k < 0) {
k = m;
}
}
return 0;
}
And my output for first 10 permutations is:
aaaaa
aaaaab
aaaaac
aaaaad
aaaaae
aaaaaf
aaaa
aaaaba
aaaaca
aaaada
Any suggestions?
(Showing a different idea)If you look carefully you will see that all the permutations are the numbers in base-7. Consider a as 0, b as 1 and so on. So for every number 1..n you will convert it into base 7 and write it (By write it I mean, in place of 0 you put a,1 - b etc). That will give you the required result. (Ofcourse in conversion you will have to append 0 to the left of the number as per number of digits you want to show). There are problems in your code:
char s[6]="abcdef";
is legal in C.
s[6]=0;
This is not as you are accessing array index out of bound which is Undefined behavior. strlen(t) is undefined behavior as t is not NUL terminated.
Also you have fprintf(c,"%s ",t); in your code - this also leads to undefined behavior, it also expects a char* which points to a nul terminated char array. This will make your realize that how irrelevant it is to have something like this
char s[6]="abcdef";
Long story short, use char s[7]="abcdef"; (same applies to t also).

how to modify detab to accept list of arguments

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define TAB_STOP 8
/* replaces tabs from input with the proper amount of blank spots */
int Detab()
{
int c, x;
int column;
x = column = 0;
while((c=getchar())!=EOF)
{
if(c == '\n') /* reseting counter if newline */
{
putchar(c);
return 1;
}
else if(c!='\t') /* column counts places to tab spot */
{
putchar(c);
column++;
if(column == TAB_STOP)
column = 0;
}
else /* tab */
{
for(x=0; x<TAB_STOP - column; x++)
putchar('_');
column = 0;
}
}
return 0;
}
#define MAX_ARGUMENTS 100
int main(int argc, char *argv[])
{
int i, val = 0;
int nums[MAX_ARGUMENTS];
int x = 0;
for(i = 1; i < argc; i++) {
while(isdigit(*argv[i])) {
val = val * 10 + *argv[i] - '0';
*++argv[i];
}
if(x > MAX_ARGUMENTS - 1)
return 0;
nums[x++] = val;
nums[x] = '\0';
val = 0;
}
while(Detab(nums));
printf("Press any key to continue.\n");
getchar();
return 0;
}
In main i put all the arguments(numbers) inside nums array and then pass it to detab. So now im interested what would be the smart way to edit detab so it works. I'm still trying to figure out for a working pseudocode but i dont really know.
The way i tought it should work is:
if arguments are 5, 8, 10 then a tab inside first 4 characters leads to position 5, in 5 - 7th char leads to pos 8 etc.
In case of a newline, the arguments start all over again from the begining.
The most common way is to have Detab accept a pointer (which points to an element in an array) and the length of that array:
int Detab(int* data, int len); // access data[0] through data[len - 1]
Call it like so:
void example() {
int array[] = {5, 8, 10};
Detab(array, 3);
// or:
Detab(array, sizeof array / sizeof *array); // second parameter evaluates to 3
// without using a magic constant
}
Here's some pseudocode for expanding tabs:
def expandtabs_in_line(line, tabstops, default, space):
result = ""
for c in line:
if c != "\t":
result += c
else:
for stop in tabstops:
if stop > len(result):
result += space * (stop - len(result))
break
else:
result += space * (default - (len(result) % default))
return result
def expandtabs(lines, tabstops=[], default=8):
for line in lines:
yield expandtabs_in_line(line, tabstops, default, " ")
Try it out at codepad.

Resources