Program won't store characters in 2d array in c - c

I am creating a program where I insert a number of sentences and the program outputs them in order. I have finished the program, but when I run it it seems like the characters I input into the array aren't displayed or stored correctly, getting as a result random letters instead of the full sentence. Here is the code of the program:
char ch;
int i,j,k;
int nothing = 0;
int count = 1;
char lines[5][256];
int length[256];
int main() {
printf("Please insert up to a max of 5 lines of text (Press enter to go to next line and twice enter to stop the program):\n");
i = 0;
while (i<5){
j = 0;
ch = getche();
if (ch == '\r'){
if(i!= 0){
break;
}
printf("You have not inserted anything, please insert a line:");
i=-1;
}
if(ch != '\r'){
lines[i][j]=ch;
while (ch!='\r'){
ch = getche();
lines[i][j] = ch;
j++;
}
}
printf("\n");
i++;
}
for (k=i ; k > 0; k--){
printf("\tphrase %i :", count);
for ( j =0 ; j <= length[k]; j++){
printf("%c",lines[j][k]);
}
count++;
printf("\n");
}
return 0;
}
How can I get the characters to be stored and displayed correctly? Any help is appreciated, thank you!!

There are numerous problems with your code. I'll try and summarise here, and give you improved code.
Fist, some changes that I made to get this to compile on my system:
Changed getche() to getchar() (getche() does not appear to be available on Ubuntu).
I took out the section about re-entering a string, and just focused on the rest (since the logic there was slightly broken, and not relevant to your question). It will still check for at least one line though, before it will continue.
I had to change the check for \r to \n.
I changed your length array to size 5, since you'll only have the lengths of maximum 5 strings (not 256).
Some problems in your code:
You never updated the length[] array in the main while loop, so the program never knew how many characters to print.
Arrays are zero indexed, so your final printing loops would have skipped characters. I changed the for parameters to start at zero, and work up to k < i, since you update i after your last character in the previous loop. The same with j.
Your reference to the array in the printing loop was the wrong way around (so you would've printed from random areas in memory). Changed lines[j][k] to lines[k][j].
No need for a separate count variable - just use k. Removed count.
The nothing variable does not get used - removed it.
#include <stdlib.h>
#include <stdio.h>
char ch;
int i,j,k;
char lines[5][256];
int length[5];
int main()
{
printf("Please insert up to a max of 5 lines of text (Press enter to go to the next line and twice enter to stop the program):\n");
i = 0;
while (i<5)
{
j = 0;
ch = getchar();
if ((ch == '\n') && (j == 0) && (i > 0))
{
break;
}
if (ch != '\n')
{
while (ch != '\n')
{
lines[i][j] = ch;
j++;
ch = getchar();
}
}
length[i] = j;
printf("\n");
i++;
}
for (k = 0; k < i; k++)
{
printf("\tPhrase %i : ", k);
for (j = 0; j < length[k]; j++)
{
printf("%c", lines[k][j]);
}
printf("\n");
}
return 0;
}

Related

Printing lowercase, uppercase, and number of numbers

#include<stdio.h>
int main() {
char text[1000];
int ch;
int index = 0;
while ((ch = getchar()) != EOF) {
text[index] = ch;
index++;
}
text[index] = '\0';
int i =0;
int num_Count=0;
int lower_Count=0;
int upper_Count =0;
while(i < index) {
if((text[i]>='0') && (text[i]<='9')){
num_Count ++;
i++;
}
else if((text[i]>='A') && (text[i]<='Z')){
upper_Count++;
i++;
}
else if((text[i]>='a') && (text[i] <='z')){
lower_Count++;
i++;
}
else
i++;
}
printf("%d %d %d", num_Count, lower_Count, upper_Count);
return 0;
}
It is a program that outputs the number of lower case, upper case, and number when the sentence is inputted.
For example,
Hi
Name
100
Would output 3 4 2
I keep seeing a runtime error.
The (while) part seems to be wrong.. I do not know what's wrong.
I ran your code in my system and checked for the input: Hi Name 100. The output I got is 3 4 2 which is the expected output. I feel the only place where the code can run in an infinite loop is while reading the inputs. Try to use ctrl+ d for EOF or ctrl+ z for windows.
Rest every thing is fine.
EOF means End Of File. It is used when you read data from a file. I suggest put a character like newline ('\n').

C program stuck in infinite-loop-like nautre but without printing any variables

I'm trying K&R exercise 1-29 and honestly I'm stumped by what my program is doing. Upon inputting a small text file with gcc, the program just runs forever as if there's an infinite loop. Reading through my loops again I can't see any obvious mistakes, so I tried to print different variables to see what's happening, but nothing's printing to the command line - even the variable i from the very first for loop, not even once. Here's my code:
#include <stdio.h>
#define tabStop 10
#define maxInput 1000
int main(){
int i, c, b;
int m, t = 0;
int index, index2;
char input[maxInput];
int nonBlank;
for (i = 0; i<maxInput-1 && (c=getchar()) != EOF; ++i){
if (c != ' '){
input[i] = c;
}
else {
index = i; /*stores location in character array at start of blanks*/
for (b = 0; c == ' '; ++b, ++i); /*counts the number of blanks (b) until the next non-blank character*/
nonBlank = input[i]; /*saves the first seen non-blank character to be re-added later (as getchar() will have taken it in from input and will now stay at that point of the input)*/
index2 = i; /*stores location in character array at end of blanks*/
if (b >= tabStop){ /*if the tab space fits inside the number of blanks, otherwise there is nothing to be done*/
while (t < b){
t += tabStop;
++m;
}
for (int x = 0, i = index; i != index2 && x <= m; ++i, ++x){ /*loops over the number of tabs to be added starting from the first blank in the array found up until the first non-blank*/
input[i] = '\t';
}
while (i != index2){ /*if i did not reach index2 before x surpassed m, there exist remaining spaces to be filled with blanks*/
input[i] = ' ';
++i;
}
}
input[i] = nonBlank; /*puts the first seen non-blank character into place, as getchar() has already covered it and so it wouldn't otherwise be added like other non-blanks*/
}
}
input[i] = '\0';
printf("%s", input);
return 0;
}
Here's the inputted text file:
hello there world

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.

The first char of my output is omitted in C

I can't seem to figure out what is going on with my output. I am reading in multiple lines of user input and outputting corresponding input that exceeds a lower boundary. For some reason when I output, the string that's outputted is omitting the first character of the string. Can anyone tell me why this is occuring?
#include <stdio.h>
typedef struct{
char name[4];
int population;
} state;
enum { MAX_STATES = 10 };
int main()
{
state myStates[MAX_STATES];
int c;
int i = 0;
while ((c = getchar())!= EOF)
{
scanf("%s %d\n", myStates[i].name, &myStates[i].population);
i++;
}
// printf("Last character is [%d]\n", c);
printf("");
if (c <= 0)
{
for(int j = 0; j <= MAX_STATES; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
}
return 0;
}
Input:
TX 23
CA 45
Output:
X 23
A 45
Updated Code:
#include <stdio.h>
typedef struct{
char name[4];
int population;
} State;
enum { MAX_STATES = 10 };
int main()
{
State myStates[MAX_STATES];
int i, j;
// Function to read in multiple lines (up to 10) of user input; loop
// controls in place, detects format problems, prevents string buffer
// overflows.
for (i = 0; i < MAX_STATES; i++)
{
if (scanf("%2s %d\n", myStates[i].name, &myStates[i].population) != 2)
break;
}
// Function to output (stdout) array of State structs that exceed 10
// population.
for(j = 0; j < i; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
return 0;
}
The output as posted, only goes until there is an input that is less than 10 and it breaks out of the loop. When I didn't have that break statement, I was getting garbage output at the last line. Any suggestions to improve the output?
Replace:
int i = 0;
while ((c = getchar()) != EOF)
{
scanf("%s %d\n", myStates[i].name, &myStates[i].population);
i++;
}
with:
int i;
for (i = 0; i < MAX_STATES; i++)
{
if (scanf("%3s %d", myStates[i].name, &myStates[i].population) != 2)
break;
}
This protects you against entering too many states, uses the for loop to put the loop controls in place, detects format problems, prevents string buffer overflows, and reads the first character into the name. Also, a trailing white space (such as a blank or newline) in a format string is a very bad idea in a scanf() format string if the input is being entered interactively. If the input comes from a file, it is less serious but still unnecessary most of the time. (See Trailing blank in scanf() format for more information.)
Keeping a while loop
If you're really adamant that you need a while loop, then you can use:
int i = 0;
while (i < MAX_STATES && (c = getchar()) != EOF)
{
ungetc(c, stdin);
if (scanf("%3s %d", myStates[i].name, &myStates[i].population) != 2)
break;
i++;
}
or:
int i = 0;
while (i < MAX_STATES && (c = getchar()) != EOF)
{
myStates[i].name[0] = c;
if (scanf("%2s %d", &myStates[i].name[1], &myStates[i].population) != 2)
break;
i++;
}
Note that these while loops still maintain both lots of overflow protection — overflowing the main array, and overflowing the name field. Note that one of the two scanf() statements uses %3s and the other %2s; you should be able to explain why. (And yes, the null byte is not counted by scanf(), so you have to use an 'off-by-one' length in the conversion specification.)
There are, no doubt, other techniques that could also be used. However, I think you'll find that the for loop is more nearly idiomatic C.
One alternative that is often sensible is to use fgets() (or POSIX getline() if it is available) to read whole lines, and then sscanf() to parse the lines. This often leads to more resilient programs, and better error reporting. It also stops people who try to put the information for all 50 states on a single line, or who put each datum on a separate line with a blank line in between them all, from getting away with the malformed data. You can quietly insist on two fields (and, if you're careful, only two fields) on the line.
And the output code?
May I inquire about a suggestion for displaying the output properly?
You have:
printf("");
if (c <= 0)
{
for(int j = 0; j <= MAX_STATES; j++)
{
if(myStates[j].population >= 10)
printf("%s %d\n", myStates[j].name, myStates[j].population);
else
break;
}
}
The first printf() does nothing; it should go. The if (c <= 0) condition is a bit dubious. It is possible to type a null byte (often Control-# or Control-Shift-2), though it would be a bit hard to get that to break the original loop. The for loop should be more like for (int j = 0; j < MAX_STATES; j++) — this is the template for safe for loops in C. You most frequently use for (int i = 0; i < MAX; i++). However, you only want to print the states that were read, so instead of using MAX_STATES, you need to use i as the limit. If you really only want to print the top 9 states (CA, TX, FL, NY, IL, PA, OH, GA, NC — see Wikipedia; Michigan is just shy of 10M, it says), then the if condition is fine.
So, you could use (noting that the input loop sets i to the number of states read successfully):
for (int j = 0; j < i; j++)
printf("State: %.2s, Pop'n: %dM\n", myStates[j].name, myStates[j].population);
You can tweak the format to suit your requirements, of course. This will print nothing if no states were read, or the number of states that were read. If you really want to apply the condition on the population, then you'd use:
for (int j = 0; j < i; j++)
{
if (myStates[i].population >= 10)
printf("State: %.2s, Pop'n: %dM\n", myStates[j].name, myStates[j].population);
}
An alternative is:
int i = 0;
char temp[100];
for(i=0; i<MAX_STATES; i++){
fgets(temp, 100, stdin);
if(strcmp(temp, "\n") == 0)
break;
sscanf(temp, "%s %d\n", myStates[i].name, &myStates[i].population);
}
You could try adding a space before %s in scanf, or specify a strict number of chars.
scanf(" %3s",
Or even use as in Beej's guide:
// read all whitespace, then store all characters up to a newline
scanf(" %[^\n]", s);
You could try adding a space before %s in scanf, or specify a strict number of chars.
Or even use this:
// read all whitespace, then store all characters up to a newline
scanf(" %[^\n]", s);

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?

Resources