Two identical loops but the second one continues infinitely - c

Expected output of program is to print a border of a specified character around a sentence input by the user.
//program: border.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int argu = argc - 1;
if(argu < 1){
printf("usage: border arguments are the text to border.\n");
}
else{
printf("Enter the character for the border: ");
char in = getchar();//get the character input by user
int size;
for(int i = 1; i <= argu; i++){// gets the count of the characters in the string
size += strlen(argv[i]);
size += 1; //to compensate for spaces
}
printf("%d", size);
printf("\n");
size += 2;
for( int a = 0; a <= size ; a++){
printf("%c", in); // prints the first border line
}
printf("\n");
printf("%c%*c\n", in, size, in);//prints second line of border line.
printf("%c", in);
printf(" ");
for( int i = 1; i <= argu; i++){//prints the sentence that was typed.
printf("%s " , argv[i]);
}
printf("%c", in);
printf("\n");
printf("%c%*c\n", in, size, in);// same as the second line.
printf("%d", size);
for( int b = 0; b <= size ; b++){ //causing the infinite loop
printf("%c", in);
}
printf("\n");
}
return 0;
My first loop works fine:
for( int a = 0; a <= size ; a++){
printf("%c", in); // prints the first border line
}
but when I included the second one, which is identical, it caused my program to continue infinately.
for( int b = 0; b <= size ; b++){
printf("%c", in);
}

As was mentioned in the comments, you never initialize size which means it has some random value. So you end up printing a number of border characters equal to that random value plus the intended length of the border.
If you do this:
int size = 0;
That will solve the problem. Sample input/output:
[dbush#db-centos tmp]$ ./x1 test text
Enter the character for the border: x
10
xxxxxxxxxxxxx
x x
x test text x
x x
12xxxxxxxxxxxxx
So now we see that there's a number stuck at the bottom border. That's because you're printing size before the bottom border, so you should move that printf to after the loop to print that border.
So change this:
printf("%c%*c\n", in, size, in);// same as the second line.
printf("%d", size);
for( int b = 0; b <= size ; b++){ //causing the infinite loop
printf("%c", in);
}
To this:
printf("%c%*c\n", in, size, in);// same as the second line.
for( int b = 0; b <= size ; b++){ //causing the infinite loop
printf("%c", in);
}
printf("%d", size); // this line moved down

Related

printing * corresponding to the number of iteration

So in C I'm supposed to let the user input an integer n from the interval [5, 25]. And then, for every number from 1 to n, in a new line print that many stars so it would look something like this:
*
**
***
I tried doing it like this, but it's not working. What am I doing wrong here?
#include <stdio.h>
int main(void)
{
int n, i;
char star = '*';
do {
printf("Input an int from [5, 25]");
scanf("%d", &n);
} while (n < 5 || n >= 25);
for (i=0; i < n; i++){
star += '*';
printf("%c", star);
}
return 0;
}
You cannot write star += '*'; because you declared star as a char, C is strongly typed, a char is a char not a table of char.
You have to use nested loop, like this for example:
#include <stdio.h>
int main(void)
{
int n, i, j;
char star = '*';
do
{
printf("Input an int from [5, 25]");
scanf("%d", &n);
} while (n < 5 || n >= 25);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= i; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
You need nested loops
for (int i=0; i < n; i++)
{
for(int j = 0; j <= i; j++)
printf("*");
printf("\n");
}
or if you want to use strings:
char str[n + 1];
for (int i=0; i < n; i++)
{
str[i] = '*';
str[i + 1] = 0;
puts(str);
}
https://godbolt.org/z/aT8brP1ch
The statement
star += '*';
is not the correct way to concatenate two strings in C. In order to do this, you can define an array with sufficient space for the string and use the function strcat, like this:
#include <stdio.h>
#include <string.h>
int main(void)
{
int n;
//initialize "stars" to an empty string
char stars[20] = {0};
do {
printf("Input an int from [5, 25]: ");
scanf("%d", &n);
} while (n < 5 || n >= 25);
//build the string containing the stars using repeated
//string concatentation
for ( int i = 0; i < n; i++ ) {
strcat( stars, "*" );
}
//print the string
printf( "%s\n", stars );
return 0;
}
This program has the following behavior:
Input an int from [5, 25]: 5
*****
However, this is highly inefficient and unnecessarily complicated. Instead of first building the string in an array before printing it out all at once, it is usually easier to simply print it one character at a time:
#include <stdio.h>
#include <string.h>
int main(void)
{
int n;
do {
printf("Input an int from [5, 25]: ");
scanf("%d", &n);
} while (n < 5 || n >= 25);
//print the stars one character at a time
for ( int i = 0; i < n; i++ ) {
putchar( '*' );
}
//end the line
putchar( '\n' );
return 0;
}
This program has the same output as the first program.
You now have the solution for printing out a single line. However, your task involves printing out several lines. This will require a nested loop. In accordance with the community guidelines on homework questions, I will not provide the full solution at this time, as you should attempt to do this yourself, first.
char is an integral type - that is, it represents a number. '*' is a Character Constant, which actually has the type int.
char star = '*';
star += '*';
In ASCII, this is no different from
char star = 42;
star += 42;
A string is a series of nonzero bytes, followed by a zero byte (the null terminating character, '\0'). You cannot build a string by adding two integers together.
To build a string, you must place each byte in a buffer in sequence, and ensure a null terminating byte follows.
#include <stdio.h>
#define MIN 5
#define MAX 25
int main(void)
{
int n;
do {
printf("Input an int from [%d, %d): ", MIN, MAX);
if (1 != scanf("%d", &n)) {
fprintf(stderr, "Failed to parse input.\n");
return 1;
}
} while (n < MIN || n >= MAX);
char buffer[MAX + 1] = { 0 };
for (int i = 0; i < n; i++) {
buffer[i] = '*';
buffer[i + 1] = '\0';
puts(buffer);
}
}
Aside: never ignore the return value of scanf.
Or you can avoids strings, and just print the characters directly.
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++)
putchar('*');
putchar('\n');
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int n,i,j;
printf("enter a number between 5 & 25");
scanf("%d",&n);
for(i=1;i<=n;i++){
for(j=1;j<=i;j++){
printf("*");
}
printf("\n");
}
return 0;
}
String concatenation does not work like that in C, instead use strcat().

I want to output * as a number and repeat the output as many times as I have entered

I got a problem of completing the code below.
#include <stdio.h>
void triR(void)
{
int size, repeat;
scanf("%d %d", &size, &repeat);
printf("Hello world\n");
// ...
// Complete this function
// ...
printf("Bye world\n");
}
Example of function excution
The above three are the input values.
I think The first is the minimum size of the number (I do not know why it does not work if I do not enter 1), the middle is the maximum size of the number, and the last is the number of iterations of the input value.
After looking at the example, I created the following code
#include <stdio.h>
#include <stdlib.h>
void triR(void)
{
int size, repeat;
int num;
scanf("%d %d", &size, &repeat);
printf("Hello world\n");
for (int b = 0; b < size; ++b) //b = horizontal line, a = number
{
for (int a = 0; a <= b; ++a)
{
for (num = 1; num <= a; ++num) - failed sentences
{
printf("%d", num);
}
}
printf("\n");
}
for (int k = size; k > 0 ; --k) //k = horizontal line, i = number
{
for (int i = 1; i < k; ++i)
{
{
printf("*"); -Sentences that were successfully run using *
}
}
printf("n");
}
// for (int c =o; ) - sentences tried to make about repeating output value
printf("Bye world\n");
return 0;
}
I know my code looks a lot strange.
I didn't have the confidence to make that code in numbers, so I tried to make it * and convert it.
It succeeded in running by *, but it continues to fail in the part to execute by number.
There is no one to ask for help, but I am afraid that I will not be able to solve it even if I am alone in the weekend. I can not even convert numbers far repeated outputs. I would really appreciate it even if you could give me a hint.
The above code I created(Failed)
Code with *
I'd like to say that even though I managed an implementation, it is definitely neither efficient nor practical. I had to restrict your size variable to digits, as I used ASCII to convert the numbers into characters and couldn't use the itoa() function, since it's not standard.
#include <stdio.h>
#include <stdlib.h>
void triR(void) {
int size, repeat;
scanf("%d %d", &size,&repeat);
printf("Hello world\n");
// string size of n^2+2n-1
char* print_string = malloc((size*size+2*size-1)*sizeof(char));
unsigned int number = 1;
unsigned int incrementer = 1;
while (number < size) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number++;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
while (number > 0) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number--;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
for (int i = 0; i < repeat; i++) {
printf("%s\n", print_string);
}
printf("Bye world\n");
free(print_string);
}
I allocated a char* with the size of size^2+2size-1, as this is the size required for the newline and number characters.
The variables number and incrementer are unsigned and start at 1 as they don't need to go below 1.
I put two while loops with similar code blocks in them:
while (number < size) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number++;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
while (number > 0) {
for (int i = 0; i < number; i++) {
*(print_string+i+incrementer-1) = 48+number;
}
incrementer+=number;
number--;
*(print_string+incrementer-1) = '\n';
incrementer++;
}
The first loop goes up to the size and inserts the characters into the char* in their positions. When the number is done, it increments the incrementer and adds the newline character.
The second loop goes down in number, doing the same things but this time decrementing the number variable. These two variables start at 1, as that's the start of the "pyramid".
*(print_string+i+incrementer-1) = 48+number;
There is a restriction here, in that if you exceed the number 9 your output will print whatever the ASCII representation of 58 is, so if you want to go above 9, you need to change that.
The for loop just prints the final string "repeat" times as wanted. The newline in the printf() function is not necessary, as the final string contains a newline character at the end, I left it in though. The downside of this implementation is that you're using a char* rather than some other sophisticated method.
Dont forget to free the char* when you're done, and don't forget to add user input error-checking.
#include <stdio.h>
#include <stdlib.h>
void clear(FILE *stream)
{
int ch; // read characters from stream till EOF or a newline is reached:
while ((ch = fgetc(stream)) != EOF && ch != '\n');
}
int main(void)
{
int min, max, count;
while (scanf("%d %d %d", &min, &max, &count) != 3 || // repeat till all 3 fields read successfully and
!min || !max || !count || min > max) { // only accept positive numbers as input
fputs("Input error!\n\n", stderr); // and make sure that the max is greater than the min
clear(stdin); // remove everything from stdin before attempting another read for values
}
puts("Hello world\n");
for (int i = 0; i < count; ++i) { // output the triangle count times
for (int row = min; row <= max; ++row) { // count row from min to max
for (int n = min; n <= row; ++n) // print row (row-min) times
printf("%d ", row);
putchar('\n'); // add a newline after every row
}
for (int row = max - 1; row >= min; --row) { // count from max-1 to min
for (int n = min; n <= row; ++n) // same as above: print row (row-min) times
printf("%d ", row);
putchar('\n'); // add a newline after every row
}
putchar('\n'); // add a newline between repetitions
}
puts("Bye world\n");
}

For Loop Not Terminating with Null Terminator

I am working on a machine problem and was tasked to input 'n' arrays that I will then have to “merge sort”.
However, when I execute and input the words, it won't stop at the 'nth' word and will ask me to input more characters even when I made use of a null terminator.
Any help would be much appreciated.
#include <stdio.h>
#include <string.h>
#include "mp1_lib.h"
int main()
{
int n;
printf("\n");
printf("Input n: ");
scanf("%d", &n);
n += 1;
char words[n][16];
initialize(n, words);
get_words(n, words);
print_words(n, words);
printf("\n");
}
void initialize(int n, char words[][16])
{
for (int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
words[x][y] = ' ';
}
}
}
void get_words(int n, char words[][16])
{
char c;
char check = '0';
for(int x = 0; x < n; x++)
{
int y = 0;
while (check != '\0' && y < 16)
{
c = getchar();
words[x][y] = c;
check = c;
y++;
}
}
}
void print_words(int n, char words[][16])
{
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
putchar(words[x][y]);
}
}
}
Since typing a null character can be tricky for the end user, I suggest you change your line to check for other character like an escape character or ESC key which value is 27 and it is easier to type
while (check != 27 && y < 16)
You cannot enter a '\0'-character, which is the same as value 0 or 0x0, through the keyboard. Hence, your loop will not terminate this way.
Usually, when getting input through the keyboard, you will terminate a single string by pressing "enter", represented by the new line character '\n' then.
You could further enhance your program to stop scanning words once an "empty" word is entered, i.e. the length of the word is 0.
See the following program, which makes use of fgets for reading in a string until the next new line character + a common code to remove the new line character itself then:
void get_words(int n, char words[][16])
{
for(int x = 0; x < n; x++)
{
if (fgets(words[x],16,stdin)){
words[x][strcspn(words[x],"\n")] = '\0'; // remove new line (if any)
}
else{
words[x][0] = '\0'; // othwise, set it to an empty string
break;
}
if (words[x][0] == '\0') // empty string entered (or end-of-file reached)
break;
}
}
void print_words(int n, char words[][16])
{
for(int x=0; x < n && words[x][0] != '\0'; x++) {
printf("%s\n",words[x]);
}
}
int main()
{
int n;
printf("\n");
printf("Input n: ");
scanf("%d\n", &n);
n += 1;
char words[n][16];
get_words(n, words);
print_words(n, words);
printf("\n");
}
Note further that your initialize-function does not terminate the strings; This will lead to undefined behaviour once you access the strings then using, for example, with printf.
Suggestion:
void initialize(int n, char words[][16])
{
for (int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
words[x][y] = ' ';
}
words[x][16-1] = '\0';
}
}

how to get space seperate array value and store it in an array? example: input in form 10 20 30 ouput:a[0]=10 a[2]=20 a[3]=30

how to get space seperated integer value in single line and store it in array variable:
input:
10 20 30
how can i store it in
a[0],a[1],a[3]
My code
#include<stdio.h>
#include<conio.h>
int main()
{
int i = 0, j, arr[100], n, x;
while(i < 100 && scanf("%d", &arr[i]) == 1)
{
i++;
}
for(j = 0; j < i; j++)
{
printf("%d\n", arr[j]);
}
return 0;
}
I assume that your problem is that your program doesn't carry on after input like:
10 20 30
The reason is that the program gets stuck in the scanf waiting for more input.
You can make the program carry on by input like:
10 20 30 x
but that is probably not what you want.
Instead you can read a whole line using fgets and the parse the line.
Something like:
#include<stdio.h>
#include<string.h>
int main()
{
char line[1000];
int i = 0, j, arr[100];
fgets(line, 1000, stdin);
char* p = line;
while(i < 100 && sscanf(p, "%d", &arr[i]) == 1)
{
i++;
// Remove leading spaces
while(*p == ' ') ++p;
// Advance to next space
p = strchr(p, ' ');
if (p == NULL)
{
// All input handled
break;
}
}
for(j = 0; j < i; j++)
{
printf("%d\n", arr[j]);
}
return 0;
}
I checked your code and the reading part actually works. I assume, however, your problem is getting out of the reading loop...
Try with a smaller array (let's say of size 3) and input numbers accordingly and you'll see; other variant: leave your big array, input three numbers and then xyz (which can't be evaluated by your scanf expression).
Problem is that if you press enter, scanf simply reads a new-line character, which is considered as any other whitespace, so scanf expects further input (try again with array of size 3 and enter three numbers, each being terminated by pressing enter and you'll see).
So you would have to scan for new line character explicitly, but that gets ugly quickly. You're better of by reading one line at once and then scan the input buffer using sscanf:
char buffer[256];
fgets(buffer, sizeof(buffer), stdin);
int i = 0, j, arr[100];
char* b = buffer;
int n = 0;
while(i < 100 && sscanf(b, "%d%n", &arr[i], &n) == 1)
{
b += n;
i++;
}
for(j = 0; j < i; j++)
{
printf("%d\n", arr[j]);
}
A variant without the line buffer could look like this:
int i = 0, j, arr[3];
while(i < 3 && scanf("%d", &arr[i]) == 1)
{
char c;
do
{
scanf("%c", &c);
}
while(isspace(c) && c != '\n');
++i;
if(c == '\n')
break;
ungetc(c, stdin);
}
for(j = 0; j < i; j++)
{
printf("%d\n", arr[j]);
}

Garbled string output

I'm currently working on an assignment which asks me to censor words of argv and input redirection.
My problem is obvious in my output which can be found below. I have a lot of tracing print statements which may or may not help you point out my issue.
My intention is:
Get file.txt
Copy contents of file.txt into buffer[x][y], where [x] is a string of word and [y] is a char of [x].
Compare argv[] arguments to buffer[][].
Create newstr[size2]. For every argv[] arguement found in buffer[][], replace it with replace[9] = "CENSORED".
Print the string of newstr[0 to (size2-1)].
Here is my code:
// censored.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define SIZE 128
int main ( int argc, char* argv[])
{
int i = 0;
int j = 0;
int k = 0;
char buffer[SIZE][SIZE];
char x;
int count = 0;
int size1 = sizeof(buffer);
int size2 = 0;
char replace[9] = "CENSORED";
int buffersize=0;
printf("tracing: size1: %d.\n", size1);
printf("tracing: argc: %d.\n", argc);
while((fscanf(stdin, "%c", &x)!=EOF))
{
if(isalpha(x))
{
buffer[i][j]=x;
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j++;
}
else if(isspace(x)) // if whitespace
{
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j = 0;
i++;
}
else if(ispunct(x)) // if x is a punctuation
{
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
}
else if(iscntrl(x)) // if control key (\n, \r etc...)
{
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c", i,j, buffer[i][j]);
j = 0;
i++;
}
else if(isdigit(x))
{
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j++;
}
else
{
break;
}
}
size2 = i;
printf("tracing: buffer[8][0]:%s\n",buffer[8]);
char newstr[size2][SIZE];
i = 0;
j = 0;
// tracing:
printf("tracing: line 72\n");
printf("tracing: size2: %d.\n", size2);
while(i < size2) //print buffer[]
{
printf("%s", buffer[i]);
i++;
}
printf("tracing: line 80\n");
for(k=1; k < argc; k++)
{
printf("%s\n", argv[k]);
}
// end tracing
i = 0; //reinitialize i
j = 0; //reinitialize j
// creating newstr[SIZE] and censoring words
printf("tracing: line 89\n");
for(i = 0; i < size2; i++)
{
for(j=1; j < argc; j++)
{
if(strcmp(buffer[i], argv[j])==0)
{
strcpy(newstr[i], &replace[0]);
printf("tracing: replaced at [%d]\n", i);
break;
}
else
{
strcpy(newstr[i], buffer[i]);
printf("tracing: copied at [%d]\n", i);
}
}
}
i = 0; //reinitialize i
while(i < size2)
{
printf("%s", newstr[i]);
i++;
}
return 0;
}
Assuming I have input redirection file named file.txt and its contents:
Said Hamlet to Ophelia,
I'll draw a sketch of thee,
What kind of pencil shall I use?
2B or not 2B?
my input is:
./censored Ophelia thee 2B < file.txt
this is the weird output I got:
Said Hamlet to CENSORED, Ill draw a sketch ???)ofoQ? ?"h?CENSORED,2oQ?
What? /oQ?kind? of 6oQ?pencil +oQ?shall ?"h?I-oQ? ???)use? ???2BoQ?
7oQoroQ Qnot 1oQ?CENSORED?4oQ?
Any help is appreciated, I know my code is messy, this is my first semester learning C.
I have good and bad news, the bad one is: I found a few errors and mistake.
The good one is: all of these are common for a beginner!
First one: The strings in buffer[] aren't terminated with a '\0' which is the end of string indicator. This is the one cause of your problem.
And here are the other ones:
char buffer[SIZE][SIZE];
Here you are considering that number of words and word's length can't be longer that 128 which will cause Segmentation Fault whenever this condition is wrong. I suggest you learn about dynamic allocation (malloc()).
for(j=1; j < argc; j++) If argc == 1, you won't enter this loop which would result in newstr being empty. Usually we end arrays with a NULL pointer and then check for every string of the array being non-null while reading the array so that we won't try to use undefined content.
As you pointed at, your code is quite messy, next time, try separating your code in functions and not coding in main().
Try reducing this, the fewer lines your write, the easier your code is to read and debug:
j = 0;
i++;
buffer[i][j]=x;//this should be buffer[i][j]
printf("tracing: buffer[%d][%d]: %c\n", i,j, buffer[i][j]);
j = 0;
i++;
This advice isn't really relevant for that kind of program designed to read a lot of data but remember: try to avoid storing data whenever you can.
I think this is enough for now, I wish you good luck and to apologize for my poor English.

Resources