Loops to put string in dictionary order - c

I have this C code:
int main()
{
char str[10];
int i,j;
printf("Enter a string\n");
scanf("%s",str);
printf("Your string: %s\n", str);
for (i=0; i<str[i];i++){
for (j = i+1; i < str[j]; j++){
if (str[j] < str[i]){
char temp = str[i];
str[i]=str[j];
str[j]=temp;
}
}
}
printf("Your ordered string: %s\n", str);
return 0;
}
The output reverses the user-inputted string. I have 2 questions:
How does expression 2 in the for loop (i<str[i]) mean that it runs until null? If str[0] = 0, shouldn't it end the loop prematurely?
For the 2nd for loop, if I change expression 2 from j<str[j] to i<str[j], it still works. Why is that?
Thank you!

How does expression 2 in the for loop (i<str[i]) mean that it runs until null? If str[0] = 0, shouldn't it end the loop prematurely?
It does not mean that. It means that it runs until i is equal to or bigger than str[i]. If you want to runt the loop until str[i] is '\0', then use condition str[i] != '\0', or simply just str[i]. In practice, your condition "works" only for short strings, and the condition itself makes no sense at all.
The reason it "works" is because for short strings, i will be smaller than any printable character for short strings. If you have a longer string and str[100] = 'a', then i<str[i] will evaluate to false, since 'a' = 97.
For the 2nd for loop, if I change expression 2 from j<str[j] to i<str[j], it still works. Why is that?
For the same reason as why the above works. In most cases both j < str[j] and i < str[j] are false only when you hit the \0-terminator. At least this is true for short strings.
Change the declaration of str to char str[200] and try longer input. You'll notice that neither of your versions will work at all.
Here is some proper code that makes sense and works, and it stops working when changing j<str[j] to i<str[j]:
int len = strlen(str);
for (i=0; i<len; i++){
for (j = i+1; j < len; j++){
if (str[j] < str[i]){
char temp = str[i];
str[i]=str[j];
str[j]=temp;
}
}
}

Related

How do you use an if else and check for last character '\0' of a string?

In C apparently strings are stored like an array with a null value or '\0' at the end. I wish to iterate over the string in a for loop and I need it to stop at '\0', not including it. I've tried many conditions for the if else and it all don't seem to work.
for example:
char patternInput[TEXTSIZE];
for(int i = 0; i<strlen(patternInput);i++)
{
if(patternInput[i]==NULL)
{
printf("\nlast character");
break;
}
else
{
printf("\n%c",patternInput[i]);
}
}
I've tried if(patternInput[i]==NULL), if(patternInput[i]==NUL),if(!patternInput[i]),if(patternInput[i]=='\0') and none of them seems to work.
If you're scanning the characters yourself, you can avoid the (redundant and somewhat expensive) strlen() call entirely, and instead use the value of patternInput[i] in the continuation-test of your for-loop:
char patternInput[TEXTSIZE] = "testing!";
for(int i = 0; patternInput[i] != '\0'; i++)
{
printf("\n%c",patternInput[i]);
}
printf("\nlast character\n");
Consider this code. This code prints 'Null character found' with position of the character. Notice the 'less than or equal to' in i<=strlen(str) in the loop invariant.
The last character at the length strlen + 1 is the '\0' character.
int i = 0;
char str[] = "Hello";
for(int i=0; i<=strlen(str); i++)
{
if(str[i]=='\0')
printf("Null character found at position %d", i);
}

Passing an array of characters as function arguments

I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
replaceChars(char str[], char sChar[], char rChar)
{
int i,j;
printf("rChar is %c", rChar);
printf("sChar is %s", sChar);
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
if(str[i] == sChar[j])
{
str[i] = rChar;
//printf("The New String is %c", str[i]);
}
}
}
printf("The New String is %s", str);
}
void main()
{
char myString[36], schar[36], rchar;
printf("Please enter a string:");
scanf("%[^\n]s", &myString);
printf("Which characters to replace?");
scanf(" %[^\n]c", &schar);
printf("With which character?");
scanf(" %[^\n]c", &rchar);
replaceChars(myString, schar, rchar);
}
Two issues here.
First, when you loop through str and sChar:
I am trying to pass a string as an argument to a function and it throws a Segmentation fault(Core Dumped) error. Could you please let me know what mistake I am making here? Here is the code:
for(i = 0; i <= strlen(str); i++)
{
for(j = 0; j <= strlen(sChar); j++)
{
You use <= as your exit condition. Array indexes start from 0, so valid indexes are from 0 to length-1. You're going from 0 to length, so you're stepping of the end of the array. Reading past the end of an array invokes undefined behavior.
Change the conditions to use <:
for(i = 0; i < strlen(str); i++)
{
for(j = 0; j < strlen(sChar); j++)
{
The second problem is in how you're reading the values:
scanf("%[^\n]s", &myString);
...
scanf(" %[^\n]c", &schar);
...
scanf(" %[^\n]c", &rchar);
The %[] format specifier doesn't require any characters after it, and it requires a char * as a parameter which points to the first element of an array of char. In the first two cases, you're passing the address of an array instead of the array itself (which decays to a pointer) and you have an extra character after the %[] format that isn't needed. In the third case you pass a pointer to a single char when a pointer to multiple characters is expected by the format. Because you want to read a single char, you want to use the %c format specifier instead.
scanf("%35[^\n]", myString);
...
scanf(" %35[^\n]", schar);
...
scanf(" %c", &rchar);
Note also that the first two have a field width that limits the number of characters that are read so that you don't overrun the arrays.
Could you please let me know what mistake I am making here?
In addition to #dbush good answer, OP's code is unnecessarily inefficient.
Using the corrected code below, and assume the initial length of the str, sChar are S,C respectively.
for(i = 0; i < strlen(str); i++) {
for(j = 0; j < strlen(sChar); j++) {
if(str[i] == sChar[j]) {
str[i] = rChar;
}
}
}
The for(i = 0; i < strlen(str); i++) { and with the later str[i] = rChar; obliges the code to find the length of str up to S times and each strlen(str) requires O(S) operations.
If S was a non-trivial value, say 1000, this 1000*1000 could readily affect overall performance. A simply solution is to calculate the length once or look for the null character instead.
// for(i = 0; i < strlen(str); i++) {
S = strlen(str);
for(i = 0; i < S; i++) {
// or
for(i = 0; str[i]; i++) {
The same thing happens with the inner loop too. Yet a smart compiler can see that sChar does not change and may take advantage of understanding strlen() has no side effects that would cause for a different result. With such an optimization strlen(sChar) may be truly called once, even if strlen(sChar) in inside the higher for (i...) loop.
Still it is easy and idiomatic to just test for the null character.
// for(j = 0; j < strlen(sChar); j++)
// better as
for(j = 0; sChar[j]; j++)
Yet why does this not apply to the for(i = 0; i < strlen(str); i++) loop?
Within that loop, code can modify str[] and so the compiler cannot make the optimization as with for(j = 0; sChar[j]; j++).
This also begs the question, what should code do if the replacement character rChar is the null character?
As I see it, code could either continue, replacing with a '\0 multiple times or simple return after this first.
str[i] = rChar;
if (rChar == '\0') return; // Possible way to handle \0

Printing char array with null character in the middle in C

I have noticed that when you try to print a null character in C, nothing will get printed.
printf("trying to print null\n");
printf("%c", '\0');
However, I am trying to print the characters in the following array one by one, up to the sixth character which is the null character.
char s[] = "Hello\0Bye";
int i;
for(i = 0; i < 7; i++) {
printf("%c", s[i]);
}
printf("\n");
I was expecting "Hello" to be printed, as since the sixth character is null nothing will be printed. However my output was: "HelloB".
It seems like printf skipped the null character and just went to the next character. I am not sure why the output is "HelloB" instead of "Hello".
Any insights would be really appreciated.
The construction '\0' is commonly used to represent the null character. Here
printf("%c", '\0');
it prints nothing.
And in the decalaration of s
char s[] = "Hello\0Bye";
when you print like
for(i = 0; i < 7; i++) {
printf("%c", s[i]);
}
printf() prints upto 0<7(h), 1<7(e)..5<7(nothing on console),6<7(B) iterations only and 6th charactar is B hence its prints HelloB.
I was expecting "Hello" to be printed ? For that you should rotate loop until \0 encountered. For e.g
for(i = 0; s[i] != '\0'; i++) { /* rotate upto \0 not 7 or random no of times */
printf("%c", s[i]);
}
Or even you no need to check s[i] != '\0'
for(i = 0; s[i]; i++) { /* loop terminates automatically when \0 encounters */
printf("%c", s[i]);
}
You can use below two options
1. size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
2.Iterate through each character and print it.
int i; for(i=0; i<7; i++) generates 7, not 6 iterations.
Printing \0 generates no pixels on the console (character 6) and then the 7th character (B follows).

Advice needed on loops and characters

I'm writing a simple code that will read in a series of characters which terminates upon reading in '\n' character/ typing enter. The code will also only read in a maximum of 50 characters. However, I am receiving errors when compiling, segmentation fault. I am unsure why the loop is not ending despite taking in '\n' character.
#include <stdio.h>
#include <ctype.h>
#define MAX 50
int main(void){
char str[MAX] = "0"; //initialise 1st char for the loop
int i;
printf("Enter your sentence, at most 50 character: \n");
for(i = 0; str[i] != '\n'; i++){ //terminates upon \n
str[i] = getchar();
putchar(str[i]);
}
return 0;
}
However, I tried moving the loop condition into the loop itself and use the if-break combo, it works perfectly.
#include <stdio.h>
#include <ctype.h>
#define MAX 50
int main(void){
char str[MAX] = "0"; //initialise 1st char for the loop
int i;
printf("Enter your sentence, at most 50 character: \n");
for(i = 0;; i++){ //terminates upon \n
str[i] = getchar();
putchar(str[i]);
if(str[i] == '\n')
break;
}
return 0;
}
Can any pros please explain to me why is this so and how do I correct it? Thanks a lot in advance! :)
RESOLVED. I'm checking the wrong element in the array. LOL.
Learn how for loop works.
The
for(expr1; expr2; expr3) // lack of expr2 means 'forever'
instr;
is equivalent to
expr1;
while(expr2) // expr2 is replaced with 'true' if empty
{
instr;
expr3;
}
So in your case
for(i = 0; str[i] != '\n'; i++)
the test str[i] != '\n' is calculated after the increment i++, hence it tests the wrong element of the array – the one past the one just read!
Additionally, you do not check the length of input data, so if you enter an input line longer than 50 characters, your loop will try to store the tail of a line past the end of declared array, which triggers an Undefined Behavior.
EDIT
A simple way to fulfill both criteria is to do both tests:
char str[MAX];
int i;
// print the actual value of defined maximum
printf("Enter your sentence, at most %d character: \n", MAX);
for(i = 0; i < MAX; i++){ // test the length
str[i] = getchar();
if(str[i] == '\n') // test the input char
break;
putchar(str[i]);
}
This happens because in the first case after str[i] = getchar(); ,the i++ statement executes before str[i] != '\n'; condition cheking . So the checking fails in your first code.
Try this modified for-loop:-
for(i = 0; (str[i] = getchar()) != '\n'; i++){ //Here checking happens while reading itself.
putchar(str[i]);
}
Remember that after the body of the for-loop executes, the flow of control jumps back up to the increment statement not to condition-cheking.

Creating a toUpper function in C

I'm creating my own toUpper function in C, but keep getting a segmentation fault every time I attempt to run it. Can anyone provide me with any hints as to how to fix this problem?
int toUpper(char *str)
{
int i;
for(i=0;i< i <= strlen(str); i++) {
if(str[i] >= 97 && str[i] <= 122) {
str[i] = str[i] -32;
}
}
return(str[i]);
}
int main()
{
char string[20];
printf("Enter any string:\n");
scanf("%s", string);
char result= (char)(toUpper(string));
printf("The string in upper case is:%s\n", result);
}
You're running off the end of the string:
for(i=0;i< i <= strlen(str); i++) {
^--
e.g. a 10 char string has characters 0->9, but you're looping 0->10. Change <= to < so you stop at 9.
Plus, you haven't set any limit on your scanf, so if someone enters a 21 char string, you'll exceed the storage you've allocated the string array.
Recommend changing toUpper() to:
char *toUpper(char *str) {
size_t len = strlen(str);
size_t i;
for (i = 0; i < len; i++) {
if (str[i] >= 'a' && str[i] <= 'z') {
str[i] = str[i] - 'a' + 'A';
}
}
return str;
}
Use correct index range i < strlen(str) vs. i <= strlen(str). This is the main issue. #Marc B
Change return type. Suggested by #Weather Vane. like strcpy(), strcat()
Calculate string length once, rather than many times.
Use literals that match your goal: 'a' instead of 97. #marsh
Use size_t for index and length. That is the type return by strlen() and is the best type to use for array access. Makes a difference with huge strings, but not with these simple examples.
This code does depend on ASCII. This is often OK, but not completely portable.
Change 32 to -'a' + 'A' per #user295691
printf("The string in upper case is:%s\n", result);
result should be a char * but is a char. This is probably where your seg fault is happening. Other places include:
scanf("%s", string);
if the inputted string is longer than 19 chars, you could have problems due to string only being 20 chars long
for(i=0;i< i <= strlen(str); i++) {
if str for whatever reason doesn't have an ending 0, you could seg fault there as well.
Another major issue in the code is the for loop statement.
for(i=0;i< i <= strlen(str); i++)
^ ^
It's probably a typo, but the i < i < wont work.

Resources