while loop is not breaking - c

I am not able to find out the reason for the misbehavior of the below code. This is a simple code to accept characters until either * is entered or until array size is reached and then print the characters read from the keyboard. It looks like the reading part is fine. Also if I enter * before array size is reached everything is OK. But if I do not enter * and wait until array size is reached in reading portion, I have the trouble. While printing it prints the characters read, but after that some garbage is printed. Ran through debugger, but while loop is not breaking when index is 3 or more.
int main()
{
char myStr [3];
unsigned int index=0;
printf("Enter Single characters. Enter * to stop\n");
do
{
scanf(" %c",&myStr[index]);
index++;
} while ((myStr[index-1]!='*')&&((index)<(sizeof(myStr)/sizeof(myStr[0]))));
index=0;
while ((myStr[index]!='*')&&(index<(sizeof(myStr)/sizeof(myStr[0]))))
{
printf("%c",myStr[index]);
index++;
}
printf("\n");
return(0);
}

The code runs into undefined behaviour on the printf loop's last iteration here
while ((myStr[index]!='*')&&(index<(sizeof(myStr)/sizeof(myStr[0]))))
{
...
as it in fact is doing
while ((myStr[3] ....
with myStr[3] accessing myStr out-of-bounds.
To fix this do:
while ((index < (sizeof(myStr)/sizeof(myStr[0]))) && (myStr[index] != '*'))
Boolean short-circuiting will take care of myStr[3] not being executed.

You are manipulating strings, witch need to be null-terminated.
You should use fgets(3) to get your string and then strlen(3) to get the length.
Then you can move in your string by
while (str[i] != '*' && i < strlen(str))
good luck

Related

what is wrong with my understanding of strings ie character arrays ending with '\0' element in C programming

I am a total beginner and recently started studying strings in C programming.
I understand that we need to supply the '\0' (null) character at the end of the string (to act as a end of string marker).
So if my character array is
char string[]={'H','E','L','L','O','\0'};
This makes it a 6 element array.
So I was going through this simple example of copying one string to another string. Here is the code.
#include<stdio.h>
int main()
{
char string1[80],string2[80];
int i;
printf("Enter a string \n");
gets(string2);
for(i=0; string2[i]!= '\0';i++)
{
string1[i]=string2[i];
}
string1[i]='\0'; /*here is my problem*/
printf("The copied string is \n");
printf("%s",string1);
printf("\n");
printf("The number of character are \t");
printf("%d \n",i);
}
why isn't it string1[i+1]='\0'??
I mean, isn't by putting string1[i]='\0' overwrite the last element that was just stored in the above for loop?
The code is correct, because of the way the for loop works:
for(A; B; C)
CODE;
Is equivalent to:
A;
while (B)
{
CODE;
C;
}
(Except for the use of continue, that will jump to the increment expression, not the condition, as it would happen with a while).
And since the loop ends when string2[i] != '\0', it is obvious that upon exiting, i is the index for the proper NUL byte. So after that:
string1[i] = '\0';
will write the \0 at the same place as it is in string2.
Usually for this kind of analysis it is helpful to think about preconditions and postconditions. That is, assuming there are no break and no goto, you are guaranteed that at the beginning of a for or while loop the condition is always true. And just after the end of a for or while loop the condition is always false.
Your particular code, illustrated with assert calls:
for(i=0; string2[i] != '\0'; i++)
{
asssert(string2[i] != '\0');
string1[i] = string2[i];
}
asssert(string2[i] == '\0');
string1[i] = '\0';
Looking at the code, it seems as if i is incremented as long as the character is not '\0'. So, the last time it's incremented, it increments to a new position that hasn't had a character written to it yet.
So, at the end of the loop, there's a space to write the null character to.

Given a string write a program to generate all possible strings by replacing ? with 0 and 1?

I have written this code it is working fine for a?b?c? and a?b?c?d? but for a?b?c?d?e? it is giving one additional garbage value at the end. At the end of s there is '\0' character attached then why and how is it reading that garbage value. I tried to debug it by placing printf statements in between the code but couldn't resolve it. please help.
#include<stdio.h>
void print(char* s,char c[],int l)
{
int i,j=0;
for(i=0;s[i]!='\0';i++)
{
if(s[i]=='?')
{
printf("%c",c[j]);
j++;
}
else
printf("%c",s[i]);
}
printf(", ");
}
void permute(char *s,char c[],int l,int index)
{
if(index==l)
{
print(s,c,l);
return;
}
c[index]='0';
permute(s,c,l,index+1);
c[index]='1';
permute(s,c,l,index+1);
}
int main()
{
char s[10],c[10];
printf("Enter a string.");
scanf("%s",s);
int i,ct=0;
for(i=0;s[i]!='\0';i++)
{
if(s[i]=='?')
ct++;
}
permute(s,c,ct,0);
return 0;
}
My output was like this :-
a0b0c0d0e0♣, a0b0c0d0e1♣,
...and so on.
As we can see from your code, with an array defined like char s[10] and the input being
a?b?c?d?e?
is too big an input to be held in s along with the null-terminator by
scanf("%s",s);
You need to use a bigger array. Otherwise, in attempt to add the terminating null after the input, the access is being made to out-of-bound memory which invokes undefined behaviour.
That said, never allow unbound input to the limited-sized array, always use the field-width to limit the input length (in other words, reserve the space for null-terminator), like
scanf("%9s",s);
The code is producing the correct output here, but note that it has undefined behavior for strings of size greater than or equal to 10 chars, because that's the size of your buffer.
So, for a?b?c?d?e? you need a buffer of at least 11 characters, to account for the null terminator. You should make s bigger.
See actually in C what happens in String is that everytime it appends a '\0' character at last.
Now notice in C there is nothing called string.
It's array of characters.
So if you have defined like this-
char s[10]
This actually accepts an array of less than of 9 characters as the last one will be the '\0' character.
If you add more than 9 character it will give erroneous output.

Format Specifier Q and unique bug in Mario Solution to Pyramid algorithm

Okay I have two problems with my solution to this problem, I was hoping I could get some help on. The problem itself is being able to print out #s in a specific format based on user input.
My questions are:
When I input 7, it outputs the correct solution, but when I output 8 (or higher), my buffer, for whatever reason add some garbage at the end, which I am unsure why it happens. I would add a picture but I don't have enough rep points for it :(
In my code, where I've inputted **HELPHERE**, I'm unsure why this gives me the correct solution. I'm confused because in the links I've read (on format specifiers) I thought that the 1 input (x in my case) specified how many spaces you wanted. I thought this would've made the solution x-n, as each consequent row, you'd need the space segment to decrease by 1 each time. Am I to understand that the array somehow reverses it's input into the printf statement? I'm confused because does that mean since the array increases by 1, on each subsequent iteration of the loop, it eats into the space area?
int main(void){
printf("Height: ");
int x = GetInt();
int n = 1;
int k=0;
char buff[x]; /* creates buffer where hashes will go*/
while(n<=x){ /* stops when getint value is hit*/
while(k<n) /* fill buffer on each iteration of loop with 1 more hashtag*/
{
buff[k] = '#';
k++;
}
printf("%*s",x, buff); /*makes x number of spaces ****HELPHERE*****, then prints buffer*/
printf(" ");
printf("%s\n",buff); /*prints other side of triangle */
/*printf("%*c \n",x-n, '\0');*/
n++;
}
}
Allocate enough memory and make sure the string is null terminated:
char buff[x+1];//need +1 for End of the string('\0')
memset(buff, '\0', sizeof(buff));//Must be initialized by zero
Print as many blanks as requested by blank-padding an empty string:
printf("%*s", x, "");
※the second item was written by Jonathan Leffler.
In printf("%*s",x, buff);, buff in not null character terminated.
Present code "worked" sometimes as buff was not properly terminated and the result was UB - undefined behavior. What likely happened in OP's case was that the buffer up to size 7, fortunately had '\0' in subsequent bytes, but not so when size was 8.
1) As per #BLUEPIXY, allocated a large enough buffer to accommodate the '#' and the terminating '\0' with char buff[x+1];
2) Change while loop to append the needed '\0'.
while (k<n) {
buff[k] = '#';
k++;
}
buff[k] = '\0';
3) Minor:insure x is valid.
if (x < 0) Handle_Error();
char buff[x];
4) Minor: Return a value for int main() such as return 0;.

c detecting empty input for stdin

This seems like it should be a simple thing but after hours of searching I've found nothing...
I've got a function that reads an input string from stdin and sanitizes it. The problem is that when I hit enter without typing anything in, it apparently just reads in some junk from the input buffer.
In the following examples, the prompt is "input?" and everything that occurs after it on the same line is what I type. The line following the prompt echoes what the function has read.
First, here is what happens when I type something in both times. In this case, the function works exactly as intended.
input? abcd
abcd
input? efgh
efgh
Second, here is what happens when I type something in the first time, but just hit enter the second time:
input? abcd
abcd
input?
cd
And here is what happens when I just hit enter both times:
input?
y
input?
y
It happens to return either 'y' or '#' every time when I run it anew. 'y' is particularly dangerous for obvious reasons.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#define STRLEN 128
int main() {
char str[STRLEN];
promptString("input?", str);
printf("%s\n", str);
promptString("input?", str);
printf("%s\n", str);
return EXIT_SUCCESS;
}
void promptString(const char* _prompt, char* _writeTo) {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
cleanString(_writeTo);
return;
}
void cleanString(char* _str) {
char temp[STRLEN];
int i = 0;
int j = 0;
while (_str[i] < 32 || _str[i] > 126)
i++;
while (_str[i] > 31 && _str[i] < 127) {
temp[j] = _str[i];
i++;
j++;
}
i = 0;
while (i < j) {
_str[i] = temp[i];
i++;
}
_str[i] = '\0';
return;
}
I've tried various methods (even the unsafe ones) of flushing the input buffer (fseek, rewind, fflush). None of it has fixed this.
How can I detect an empty input so that I can re-prompt, instead of this annoying and potentially dangerous behavior?
This part of cleanString
while (_str[i] < 32 || _str[i] > 126)
i++;
jumps over \0 when the string is empty.
You should add _str[i] != '\0' into the loop's condition.
To detect an empty string, simply check it's length just after the input:
do {
printf("%s ", _prompt);
fgets(_writeTo, STRLEN, stdin);
} while (strlen(_writeTo) < 2);
(comparing with two because of '\n' which fgets puts into the end of buffer)
Why do you have a bunch of variable names with leading underscores? That's nasty.
Anyway, the first thing you must do is check the return value of fgets. If it returns NULL, you didn't get any input. (You can then test feof or ferror to find out why you didn't get input.)
Moving on to cleanString, you have a while loop that consumes a sequence of non-printable characters (and you could use isprint for that instead of magic numbers), followed by a while loop that consumes a sequence of printable characters. If the input string doesn't consist of a sequence of non-printables followed by a sequence of printables, you will either consume too much or not enough. Why not use a single loop?
while(str[i]) {
if(isprint(str[i]))
temp[j++] = str[i];
++i;
}
This is guaranteed to consume the whole string until the \0 terminator, and it can't keep going past the terminator, and it copies the "good" characters to temp. I assume that's what you wanted.
You don't even really need to use a temp buffer, you could just copy from str[i] to str[j], since j can never get ahead of i you'll never be overwriting anything that you haven't already processed.

printf() isn't being executed

I wanted to write a program which counts the occurrences of each letter in a string, then prints one of each letter followed by the count for that letter.
For example:
aabbcccd -
Has 2 a, 2 b, 3 c, and 1 d
So I'd like to convert and print this as:
a2b2c3d1
I wrote code (see below) to perform this count/conversion but for some reason I'm not seeing any output.
#include<stdio.h>
main()
{
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
type=*cp;
cp++;
count=cp;
int c;
for(c=1;*cp==type;c++,cp++);
*count='0'+c;
}
count++;
*count='\0';
printf("%s",array);
}
Can anyone help me understand why I'm not seeing any output from printf()?
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
*cp is a pointer it's pointing to the address of the start of the array, it will never be == to a char '\0' so it can't leave the loop.
You need to deference the pointer to get what it's pointing at:
while(*cp != '\0') {
...
Also, you have a ; after your for loop, skipping the contents of it:
for(c=1;*cp==type;c++,cp++); <-- this ; makes it not execute the code beneath it
After fixing both of those problems the code produces an output:
mike#linux-4puc:~> ./a.out
a1b1c2cd
Not the one you wanted yet, but that fixes your problems with "printf not functional"
Incidentally, this code has a few other major problems:
You try to write past the end of the string if the last character appears once (you write a '1' where the trailing '\0' was, and a '\0' one character beyond that.
Your code doesn't work if a character appears more than 9 times ('0' + 10 is ':').
Your code doesn't work if a character appears more than 2 times ("dddd" doesn't become "d4"; it becomes "d4dd").
Probably line-buffering. Add a \n to your printf() formatting string. Also your code is very scary, what happens if there are more than 9 of the same character in a row?
1) error correction
while(*cp!='\0'){
and not
while(cp!='\0'){
2) advice
do not use array[] to put in your result user another array to put in your rusel it's more proper and eay
I tried to solve your question quickly and this is my code:
#include <stdio.h>
#define SIZE 255
int main()
{
char input[SIZE] = "aabbcccd";/*input string*/
char output[SIZE]={'\0'};/*where output string is stored*/
char seen[SIZE]={'\0'};/*store all chars already counted*/
char *ip = input;/*input pointer=ip*/
char *op = output;/*output pointer = op*/
char *sp = seen;/*seen pointer=sp*/
char c,count;
int i,j,done;
i=0;
while(i<SIZE && input[i]!='\0')
{
c=input[i];
//don't count if already searched:
done=0;
j=0;
while(j<SIZE)
{
if(c==seen[j])
{
done=1;
break;
}
j++;
}
if(done==0)
{//if i never searched char 'c':
*sp=c;
sp++;
*sp='\0';
//count how many "c" there are into input array:
count = '0';
j=0;
while(j<SIZE)
{
if(ip[j]==c)
{
count++;
}
j++;
}
*op=c;
op++;
*op=count;
op++;
}
i++;
}
*op='\0';
printf("input: %s\n",input);
printf("output: %s\n",output);
return 0;
}
It's not a good code for several reasons(I don't check arrays size writing new elements, I could stop searches at first empty item, and so on...) but you could think about it as a "start point" and improve it. You could take a look at standard library to copy substring elements and so on(i.e. strncpy).

Resources