Nested for loop isn't iterating - c

I'm trying a K and R exercise. The program is to compare two strings. If the first string has any characters that are also in string 2 then it will be deleted in string1.
The goal of my compare function below is to compare every array element in the first string with every array element in the second string. If we've got a match then we "raise a red flag" (acting as a boolean value) and we DON'T add it to the new array that will contain the edited string1. However it seems to be ignoring the second for loop. It only passes through on the k = 0 iteration for every i iteration. My other issue is that based on the output (provided beneath node) it seems that s1[i] is being assigned to s2[k]. I'm guessing this takes place in the if statement but how would that be possible? Any help anyone could provide would be very appreciated.
I used the GNU GCC compiler if it makes a difference.
#include <stdio.h>
int getLength(char s[]);
char compare(char s1[], char s2[],int s1Length, int s2Length);
int main()
{
char stringOne[] = {'a','b','c','d','e'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z'};
int lengthOne;
int lengthTwo;
lengthOne = getLength(stringOne);
char theResultingString[lengthOne];
lengthTwo = getLength(stringTwo);
compare(stringOne, stringTwo, lengthOne, lengthTwo);
return 0;
} //end of main.
int getLength(char s[]) //getLength gives us the length of each and every string
{
int i=0;
for(i = 0; s[i]!='\0'; i++) {
} //end for loop
return i;
} //end of getLength
char compare(char s1[], char s2[],int s1Length, int s2Length)
{
int redFlagRaised = 0; //This will be used as a boolean indicator if we have a matching element
char toBeReturned[s1Length];
int i;
int k;
for(i = 0; i<s1Length; i++) {
printf("i is now %d\n",i);
for(k = 0; k<s2Length; k++) {
printf("k is now %d\n",k);
if(s1[i] = s2[k]) { //If at any point the s1 char being examined equals any of s2 chars then
printf("s1[i] is %c\n",s1[i]);
printf("s2[i] is %c\n",s2[i]);
redFlagRaised = 1; //we raise the red flag!
} //end first inner if statement
if((k=(s2Length-1))&&(redFlagRaised = 0)) { //if we reach the end and we DON'T have a red flag then
toBeReturned[i] = s1[i];
printf("toBeReturned[0] is %c\n",toBeReturned[0]);
} //end second inner if statement
} //end inner for loop
redFlagRaised = 0; //We lower the flag again for the next inner for loop iteration
} //end outer for loop
printf("The result is %c", toBeReturned[0]);
return toBeReturned[0];
} //end of compare
Output:
i is now 0
k is now 0
s1[i] is P
s2[i] is P
i is now 1
k is now 0
s1[i] is P
s2[i] is f
i is now 2
k is now 0
s1[i] is P
s2[i] is g
i is now 3
k is now 0
s1[i] is P
s2[i] is c
i is now 4
k is now 0
s1[i] is P
s2[i] is t
i is now 5
k is now 0
s1[i] is P
s2[i] is y
The result is �
Process returned 0 (0x0) execution time : 0.005 s
Press ENTER to continue.

char stringOne[] = {'a','b','c','d','e'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z'};
These are not strings. You need to terminate them using null character.
Try this -
char stringOne[] = {'a','b','c','d','e','\0'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z','\0'};
Also in this condition-
if(s1[i] = s2[k])
use == instead of =(this is assignment operator).So condition should be written as -
if(s1[i]==s2[k])
Similarly in this condition (as mentioned by Weather Vane Sir in comment)if((k=(s2Length-1))&&(redFlagRaised = 0)) use ==
if((k==(s2Length-1))&&(redFlagRaised == 0))

In compare function in IF condition you are assigning the value to K like bleow
if((k=(s2Length-1))&&(redFlagRaised = 0)){ //if we reach the end and we DON'T have a red flag then
toBeReturned[i] = s1[i];
printf("toBeReturned[0] is %c\n",toBeReturned[0]);
}
But it's needs to be like this
if((k==(s2Length-1))&&(redFlagRaised == 0)){ //if we reach the end and we DON'T have a red flag then
toBeReturned[i] = s1[i];
printf("toBeReturned[0] is %c\n",toBeReturned[0]);
}
You have to use Compare operator (==) not assignment operator(=)
In below code
char stringOne[] = {'a','b','c','d','e'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z'};
These are not strings. You need to terminate them using null character. Try this -
char stringOne[] = {'a','b','c','d','e','\0'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z','\0'};
Below also use this == operator instead of = operator
if(s1[i] = s2[k])

Related

Can someone explain why to[i] = '\0' is correct?

It's a function that should copy a given string into another string. Can someone explain me why to[i] = '\0' is correct without ++ to i after the loop has stop and what ++ means before and after i.
#include <stdio.h>
void copyStringArr(char to[], char from[]);
int main(void)
{
char string1[] = "A string to be copied";
char string2[250];
copyStringArr(string2, string1);
printf("%s\n", string2);
return 0;
}
void copyStringArr(char to[], char from[])
{
int i;
for(i = 0; from[i] != '\0'; i++)
to[i] = from[i];
to[i] = '\0';
}
Let's copy a 2-char string ("hi") instruction by instruction ..
// from = "hi"
// to = "HERE BE DRAGONS..." // garbage
i = 0;
from[0] != 0 // is true
to[0] = from[0]; // to = "hERE BE DRAGONS..."
i++ // i is 1 now
from[1] != 0 // is true
to[1] = from[1]; // to = "hiRE BE DRAGONS..."
i++ // i is 2 now
from[2] != 0 // is false, so exit loop
to[2] = 0; // terminate string, don't care about i anymore
// to = "hi"; the DRAGONS (the initial garbage) are
// still in memory, you need "special tricks" to see them
Because for loops are executed as:
Execute once: i = 0;.
Then loop:
Check from[i] != '\0'
Execute loop body.
Execute i++.
The last full lap of the loop executes i++ and then the next from[i] != '\0' check yields true. That's where it stops and i was already incremented so that its value corresponds to the index of the null terminator.
You can illustrate it with this code that uses the comma operator to sneak in a printf at each of the mentioned steps:
for(int i=(printf("[i=0]\n"),0);
printf("[i<3] "), i<3;
printf("[i++]\n"), i++)
{
printf("[loop body i: %d] ", i);
}
Output:
[i=0]
[i<3] [loop body i: 0] [i++]
[i<3] [loop body i: 1] [i++]
[i<3] [loop body i: 2] [i++]
[i<3]

Print array of strings vertically

I know how to print a single string vertically.
char test[100] = "test";
int i;
for(i=0;i<strlen(test);i++){
printf("%c\n",test[i]);
}
Which will give me:
t
e
s
t
But how can I print an array of strings vertically? For example:
char listOfTest[2][10] = {"testing1","quizzing"};
So it can return:
tq
eu
si
tz
iz
gi
1g
Simply loop through the first string and print each character at index i in the first string and the second string till you reach the null terminator of first string
NOTE: this only work when string 1 and string2 are equal in length and will need modification for other test cases
#include <stdio.h>
int main(void)
{
char listOfTest[2][10] = {"testing1","quizzing"};
int i = 0;
//loop through string 1 till NULL is reach
while (listOfTest[0][i])
{
//prints char at index i in string 1 and 2
printf("%c%c\n", listOfTest[0][i], listOfTest[1][i]);
//increment the index value
i++;
}
return (0);
}
Simply print a character from both strings.
(Better to test for the null character rather than repeatedly call strlen().)
for(i = 0; listOfTest[0][i] && listOfTest[1][i]; i++) {
printf("%c%c\n", listOfTest[0][i], listOfTest[1][i]);
}
To extend to n strings ...
size_t num_of_strings = sizeof listOfTest/sizeof listOfTest[0];
bool done = false;
for (size_t i = 0; listOfTest[0][i] && !done; i++) {
for (size_t n = 0; n < num_of_strings; n++) {
if (listOfTest[n][i] == '\0') {
done = true;
break;
}
printf("%c", listOfTest[n][i]);
}
printf("\n");
}

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.

C programming by K&R what does the last k>0 do in the strindex function?

From ANSI C programming by K&R (page69), there is a strindex function, which will return a position of the fisrt search-for string in the source string:
#include <stdio.h>
#define MAXLINE 1000 //max input length
int getline(char line[], int max);
int Strindex(char source[], char searchfor[]);
char pattern[] = "ould";
int main()
{
char line[MAXLINE];
int found = 0;
while (getline(line, MAXLINE) > 0)
if (Strindex(line, pattern) >= 0) {
printf("%s", line);
found++;
}
return found;
} // end of main function
int getline(char s[], int lim)
{
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
int Strindex(char s[], char t[])
{
int i, j, k;
for (i = 0; s[i] != '\0'; i++) {
for (j = i, k = 0; s[j] == t[k]; j++, k++)
;
if (k > 0 && t[k] == '\0') //here is the k
return i;
}
return -1;
}
My question is:
when j = i, k = 0; s[j] != t[k] (if the t[] and s[] are not empty strings), It seems t[0] will never get a value of \0? Then, what does this k>0 do in the last if statement?: if (k > 0 && t[k] == '\0')
If I get it right the Strindex() function checks if the string t is inside the string s.
So the if (k > 0 && t[k] == '\0') statement means that every character so far of the string t is the same with the string s and we reached the end of string t, so we got it mached and it returns the index of string s where the string t begins.
Well simply it is discarding all the 0 length targets. This is needed if you want to discard 0 length targets.(For this code. But there are better ways to do that).
Suppose s is "CODE" and t is an empty string containing \0. So in this case it enters for loop and the inner for loop breaks. And then k=0 and if that condition (k>0) is omitted if( t[k]=='\0') is used then it will be true and it is returned. But again one may argue that it should match any indices if empty target is passed.
Otherwise if t is empty then this function will return 0 as a string index. It seems to be a waste to put this condition into cycle though.
seems as it's not needed, but before touching any code from K&R, please, do full thoroughly checking.... probably it's needed. :) (edit:) indeed, that checks the case of calling strindex(3) with a null string "" second parameter to fail, instead of succeeding at the first case.
the next code always succeeds at index 0 if you call:
strindex("something", "");
without that test.
Indeed, i maintains the source string index, j is the index of the being checked char, and k is the index in the second string of the checked char (the matched length). the k > 0 test makes it fail in case the second string index is 0 as then, the null string has been tried, and it always succeeds at length 0.
The check of null string second parameter is more general, and as you can get that second string from the result of another calculation, it seems better to consider that case than to disallow it.

K&R Programming in C: EX 3.3

EX 3.3: Write a function expand(s1,s2) that expands shorthand notations like a-z in the string s1 into the equivalent complete list abc...xyz in s2 Allow for letters of either case and digits, and be prepared to handle cases like a-b-c and a-z0-9 and -a-z. Arrange that a leading or trailing - is taken literally.
I'm trying to solve exercise 3.3 in K&R and this is what I have:
void expand(char s1[], char s2[]){
int i; // index for first string
int j; // index for 2nd string
for(i = 0, j = 0; s1[i] != '\0'; ++i, ++j){
if(isalnum(s1[i]) && s1[i+1] == '-'){
char c = s1[i];
for(char c = s1[i]; c <= s1[i+2]; ++c, ++j){
s2[j] = c;
}
++i;
} else{
s2[j] = s1[i];
}
}
s2[j] = '\0';
}
It succesfully expands any range, as long as it is not after any other range, ie. it doesn't add anything to s2 after the first range is finished. If I put this statement:
printf("%c\n", c);
in the second for loop, it prints out the right characters, but it doesn't add it to s2.
Sample inputs & outputs:
In: akls aldio a-h 19 aodk
Out: akls aldio abcdefgh
In: 0-6 a-c lol
Out: 0123456
In: a-c-g 1okd 2-4
Out: abc
Can anybody point me in the right direction to fix my mistake?
Thank you.
After your inner for loop, j is one past where it should be, so you skip writing to one position. If that position happens to contain the value 0, it terminates the string and you don't see anything after it.
Also, i is one before where it should be.
Replace this:
for(char c = s1[i]; c <= s1[i+2]; ++c, ++j){
s2[j] = c;
}
++i;
With this:
for(char c = s1[i]; c <= s1[i+2]; ++c, ++j){
s2[j] = c;
}
i+=2;
j--;
As, suggested by dbush, you need to do one j--, but for cases like a-c-g to work you need to change your inner for condition too. Instead of checking c <= s1[i+2], you need to check only till c < s1[i+2]
void expand(char s1[], char s2[]){
int i; // index for first string
int j; // index for 2nd string
for(i = 0, j = 0; s1[i] != '\0'; ++i, ++j){
if(isalnum(s1[i]) && s1[i+1] == '-'){
char c = s1[i];
/* Do it c < instead of c<= */
for(char c = s1[i]; c < s1[i+2]; ++c, ++j){
s2[j] = c;
}
--j; /* Decrement j once */
++i;
} else {
s2[j] = s1[i];
}
}
s2[j] = '\0';
}
P.S: This code solves OP's immediate issues at hand (i.e the inputs that was shown in the original post). But, this code fails for inputs like a-b-c-. Also additional code is needed for inputs like abc-DEF, abc--def, abc-456, etc. However, as seen in comments (of this answer) OP wants to solve those issues himself.
As sps and dbush already made it work, let me add my two cent, too.
You should keep your stuff simple and readable if possible. For example: you load too much into your loops, its not the IOCCC. Increment/decrement only the index you defined in the first part of the for-loop. That would be the variables i and c in your case. The iterations over the vectors s1 and s2 should be done as close as possible to the vectors.
That gives:
void expand(char s1[], char s2[]){
int i;
int j;
char c;
for(i = 0, j = 0; s1[i] != '\0'; i++){
if(isalnum(s1[i]) && s1[i+1] == '-'){
for(c = s1[i]; c < s1[i+2]; c++){
s2[j++] = c;
}
i++;
} else{
s2[j++] = s1[i];
}
}
s2[j] = '\0';
}
Doing it that way gets rid of the otherwise necessary correction j--
Test it:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char s[200];
char s2[200];
int i;
memset(s,0,200);
memset(s2,0,200);
// put some spaces in between the arguments
for(i=1;i<argc;i++){
// counting ommitted!
strcat(s2,argv[i]);
s2[strlen(s2)] = ' ';
}
printf("In: %s\n",s2);
expand(s2,s);
printf("Out: %s\n",s);
exit(EXIT_SUCCESS);
}
$ gcc -W -Wall -std=c11 expand.c -o expand
./expand 0-9 ASD a-z QWE a-ch-r
In: 0-9 ASD a-z QWE a-c-r
Out: 0123456789 ASD abcdefghijklmnopqrstuvwxyz QWE abchijklmnopqr
Oh, and the ++i et al. in the third part of the for loops: we have 2016 now.

Resources