How to approach this exercise? (C) - c

"Have a program request the user to enter an uppercase letter. Use nested loops to produce a pyramid pattern like this:
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
The pattern should extend to the character entered. For example, the preceding pattern would result from an input value of E."
So far I've been doing this for a good few hours and I'm getting the 'pyramid' to format properly for the letters when iterating forwards through the alphabet with:
#include <stdio.h>
int main(void)
{
char ch = 0;
char ch2 = 0;
int rows = 0;
printf("Enter a character: ");
scanf("%c", &ch);
rows = ch - 64;
while(rows > 0)
{
int spaces;
for(spaces = rows-1; spaces > 0; spaces--)
{
printf(" ");
}
ch2 = 65;
while(ch2 < (ch-(rows-2)))
{
printf("%c", ch2);
ch2++;
}
printf("\n");
rows--;
}
}
However, I feel as though I've hit a brick wall with trying to get it to iterate backwards properly. I know it should only be a few basic loops but I'm well and truly stuck. I'm sure it's easy... I think I've just been looking at it too long. Ideas?

You are so close, you only need to take a breath and you'll see it.
When you print out your character, it has to be done after this part
while(ch2 < (ch-(rows-2)))
{
printf("%c", ch2);
ch2++;
}
or it won't fall at the end of the string. What you need is another loop that starts at the character that's one below the last character printed. It should print a character and decrement that character until it has printed the 'A' character.
Since this is homework, I'll give you a chance to write that loop before telling you the exact details.

There are ways this code could probably be rewritten to make it clearer, but basing on what you have, something like this would probably work right after your current while loop.
while (ch2 > 'A')
{
ch2--;
printf("%c", ch2);
}
I do recommend attempting to refactor your code a bit to make it clearer, though. As I suggested in a comment, start off by using character literals rather than raw integers.

You can iterate down as well as up:
while(ch2 >= 'A')
{
printf("%c", ch2);
ch2--;
}

Try this:
#include <stdio.h>
int main (int argc, const char * argv[])
{
char ch;
printf("Enter a character: ");
scanf("%c", &ch);
if(ch<'A' || ch>'Z'){
printf("Character must be between 'A' and 'Z'\n");
return 1;
}
for(int rows = ch - 'A'; rows >= 0; rows--)
{
char ch2;
for(int spaces = rows; spaces > 0; spaces--)
printf(" ");
for(ch2='A'; ch2 < (ch-(rows-1)); ch2++)
printf("%c", ch2);
for(ch2=ch2-2;ch2>='A';ch2--)
printf("%c", ch2);
printf("\n");
}
return 0;
}

Related

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.

Using scanf for character input, but the do-while loop wont stop at the null character

I'm completely new to programming (1st term in uni) and I can't keep up with my lecturer. At the moment I'm stuck on this exercise (for much more time than I'm willing to admit). I've tried to find help on the internet (in this site and others as well), but I can't, since our lecturer has us use a very simple form of c. I'm not asking necessarily for a complete answer. I'd really appreaciate even some hints about where I'm on the wrong. I understand that it might be really simple for some, that the question might seem ignorant or stupid and I feel bad for not getting what's wrong, but I need to try to understand.
So, what I'm trying to do is use scanf and a do while loop so the user can input characters in an array. But I don't understand why the loop won't stop when the user presses ENTER. There's more to the code, but I'm trying to take it slowly, step by step. (I'm not allowed to use pointers and getchar etc).
#include <stdio.h>
main()
{
char a[50];
int i;
printf("Give max 50 characters\n");
i=0;
do
{
scanf("%c", &a[i]);
i=i+1;
}
while((i<=50) && (a[i-1]!='\0'));
for(i=0; i<50; i++)
printf("%c", a[i]);
}
There aren't any nul-terminated strings here, but only string arrays.
So, when pressing enter, a[i-1] is \n not \0 (scanf with %c as parameter doesn't nul-terminate the strings, and ENTER is just a non-nul character with code 10 AKA \n)
Then don't print the rest of the string because you'll get junk, just reuse i when printing the string back:
#include <stdio.h>
main()
{
char a[50];
int i;
printf("Give max 50 characters\n");
i=0;
do
{
scanf("%c", &a[i]);
i=i+1;
}
while((i<sizeof(a)) && (a[i-1]!='\n')); // \n not \0
int j;
for(j=0; j<i; j++) // stop at i
printf("%c", a[j]); // output is flushed when \n is printed
}
Also test with i<50 not i<=50 because a[50] is outside the array bounds (I've generalized to sizeof(a))
Here is another way you can do this.
#include <stdio.h>
// define Start
#define ARRAY_SIZE 50
// define End
// Function Prototypes Start
void array_reader(char array[]);
void array_printer(char array[]);
// Function Prototypes End
int main(void) {
char user_input[ARRAY_SIZE];
printf("Please enter some characters (50 max)!\n");
array_reader(user_input);
printf("Here is what you said:\n");
array_printer(user_input);
return 0;
}
// Scans in characters into an array. Stops scanning if
// 50 characters have been scanned in or if it reads a
// new line.
void array_reader(char array[]) {
scanf("%c", &array[0]);
int i = 0;
while (
(array[i] != '\n') &&
(i < ARRAY_SIZE)
) {
i++;
scanf("%c", &array[i]);
}
array[i + 1] = '\0';
}
// Prints out an array of characters until it reaches
// the null terminator
void array_printer(char array[]) {
int i = 0;
while (array[i] != '\0') {
printf("%c", array[i]);
i++;
}
}
You may try with this code:
#include <stdio.h>
main()
{
char a[50];
int i;
printf("Give max 50 characters\n");
i=0;
do {
scanf("%c", &a[i]);
i=i+1;
} while(i<50 && a[i-1] != '\n');
a[i] = 0;
for(i=0; a[i] != 0; i++)
printf("%c", a[i]);
}
The function scanf("%c", pointer) will read one character at a time and place it at the pointer location. You are looking for '\0', which is a valid string terminator, but the newline character you get when you press ENTER and that you should be looking for is '\n'.
Also, it is a good idea to terminate the string you have read by adding a '\0' at the end (really a zero). Then use it to stop printing or you may print the "rest" of the contents of an uninitialized char array.

How can I replace getchar();?

#include <stdio.h>
int main (void)
{
int n;
printf("Give the number of words you want to input.");
scanf("%d",&n);
int letters[n],i,j,count,key,k;
char str[100];
//Scans each word, counts it's letters and stores it in the next available
//position in "letters" array.
for (i=0;i<n;i++)
{
j=0;
printf("Give the next word.");
do{
str[j] = getchar();
j++;
}while (str[j-1]!='\n');
str[j-1] = '\0';
letters[i] = j;
}
//Compacts the data by figuring out which cells have the same number of letters
for (i=0;i<n;i++)
{
key = letters[i];
count = 0;
for (j=i+1;j<=n;j++)
{
if (key==letters[j])
{
count += 1;
letters[j] = 0;
}
}
letters[i] = count;
}
//creates a histogram
i=0;
do{
printf("%d|",i);
for (j=1;j<=letters[i];j++)
{
printf("*");
}
printf("\n");
i++;
}while ((i<=n));
return 0;
}
I understand that getchar(); reads, the first enter (\n) , user hits, to give the amount of words he wants to input, and thus expects one less word.
Also, I get an infite loop for some reason at the end. Any help and ideas would be appreciated. Thanks in advance.
Change the first block of your code to look like this:
(test the output of getchar, and continues only if not EOF)
for (i=0;i<n;i++)
{
j=0;
printf("Give the next word.");
do{
a = getchar();
if(a >= 0)
{
str[j] = a;
j++;
}
else break;
}while (str[j-1]!='\n');
str[j-1] = '\0';
letters[i] = j;
}
But regarding your question: How can I replace getchar();? Have you considered using scanf()?
EDIT
Here is a simple example of using scanf() and printf() to prompt for input and then display input. It will allow user to input entire words or sentences (up to 80 characters) until 'q' is entered. Not exactly what you are doing, but you should be able to adapt it to your code... (run this)
int main(void)
{
char buf[80]={""};
while( strcmp(buf, "q") != 0) //enter a 'q' to quit
{
buf[0]=0;
printf("enter string:\n");
scanf("%s", buf);
printf("%s\n", buf);
}
}
Wouldn't it be easier to update the letter count in the first loop?
memset(letters, 0, n);
for (i=0;i<n;i++)
{
char* s = str;
int j=0;
printf("Give the next word.");
do{
*s = getchar();
++j;
}while (*(s++)!='\n');
s[-1] = '\0';
letters[j-1]++;
}
As a result the second loop will be unnecessary.
The following two lines have the wrong end condition; should be <n, not <=n. Currently they retrieve an uninitialized array element. Since you declared str as a local variable, that element is typically populated with garbage, i.e. a very big random number. That might explain why it takes extreme long (but possibly not forever) for the last loop to finish.
for (j=i+1;j<=n;j++)
}while ((i<=n));
Also, I assume line n of the histogram should contain the number of words that have n letters? That's not what you're doing right now.
letters[i] = count;
That line should have been:
letters[key] = count;
But to make that work, you should not overwrite the same array letters; you must declare a new array for your histogram, otherwise the second loop will destroy its own input.
By the way, str seems totally redundant. Is it there for debugging purposes?

Entering a letter then minus to the alphabet

i am making a program that discard a letter from a list if you enter a letter, can anyone help me. thanks.
in example:
(BEFORE)
ABCDEFGHIJKLMNOPQRSTUVWXYZ
enter a letter: A
(AFTER ENTERING A LETTER 'A')
_BCDEFGHIJKLMNOPQRSTUVWXYZ
enter a letter:
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
int main()
{
int alphabet[26];
char letter;
int i;
int j;
alphabet[0] = 'A';
for(i = 0;i < 26; i++)
{
alphabet[i] = alphabet[0];
printf ("%c", alphabet[i], alphabet[i]);
alphabet[0]++;
}
printf("\n\nenter the letter you want to remove in the alphabet: ");
scanf("%c", letter);
while(j<alphabet[i])
{
if(letter==alphabet[i])
{
j--;
}
}
}
The problem is its not removing the letter in the alphabet when i entered the letter i want to remove. please help. thanks.
EDIT: one last thing, how can i make it only one input?, i mean if i input the same letter in 2nd time it will said "you already input that letter".
You are assuming that the letters are contiguos, as in ASCII, but you cannot assume that in C.
The next line has a duplicated argument:
printf ("%c", alphabet[i], alphabet[i]);
Drop the last alphabet[i].
Your last if() sentence is wrong: the comparisson must be done with ==.
It is not clear at all what do you want to do.
EDIT:
I would do the program in this way:
#include <stdio.h>
int main()
{
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char letter;
printf("Choose a letter: ");
letter = getchar();
printf("\n\n");
for(int i = 0; i < 26; i++)
if (letter == alphabet[i])
{
alphabet[i] = '_';
break; /* This terminates the for() loop */
}
printf("Result: %s \n", alphabet);
}
EDIT2: I have changed the declaration of alphabet, because the string constant has to be modified later...
you are assigning a value to letter with the the statement
letter=alphabet[i]
this statement will always be true, unless alphabet[i] is 0.
use comparision instead
letter==alphabet[i]
also your while loop is a bit weird, as the value of j will be undefined in the beginning , so your comparision will be undefined.
while(j<alphabet[i])
{
if(letter=alphabet[i])
{
j--;
}
probably you simply want to do something like:
for(i = 0;i < 26; i++) {
if(alphabeth[i]==letter) {
alphabeth[i]='_';
}
}
if you only want to replace the first occurence of the letter, insert a break; after alphabeth[i]='_';
and you probably don't want to have magic values like "26" occuring multiple times in your sourcecode.
instead use something like
#define ALPHABETSIZE 26
and replace all occurences of 26 by ALPHABETSIZE
There are a few things here that you are doing to make it hard for yourself.
You need to use "==" not "=" to compare two variables
Your value for "j" is not initialised so "j--" would be undefined
Its probably better to keep all your types the same and make the array a "char" array not an "int" array.
To remove an element from your array "int alphabet[26];" would be very difficult, it would probably be easier to make this a "string" exercise. All you can really do is to make a "blank" letter by
alphabet[j] = ' ';
I think its possible to make a better design though if you explain your requirements more clearly :)
If I got you right you want to go through your array and check if the entered char matches any in the array.
Is there any reason, why you dont use a for-loop like this and set the array position to 0 instead of the while statement?
for(i=0;i<26;i++)
{
if(letter == alphabet[i])
alphabet[i] = "_"; // or setting it to 0 if you use and int-array
}
Or do I get something wrong here?

How do i cycle through each letter in a string?

#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';

Resources