2D array and how to print the array in C - c

I am trying to print a 2D array that should look like this
*************
*
*
*************
like a frame, but I have hard time because it is not printing the stars instead it prints numbers and even those columns I specified with 42 ('*') are not showing. I don't know if the problem is the way I am printing the array. I hope someone can help me. Thank you!
here's my code: int i,j;
int star=42;
char starchar=(char)star;
//colMax=10;
int frame[rowMax][colMax];
for(row=0;row<rowMax;row++)
{
for(column=0;column<colMax;column++)
{
frame[0][column]=starchar;
frame[9][column]=starchar;
frame[row][9]=starchar;
printf("%d%d",row,column);
}

It is printing numbers because you are passing %d%d to the printf function, which stands for decimal number. Replace %d with %c to get the character representation. See the manual for printf, e.g. at http://www.cplusplus.com/reference/cstdio/printf/
Also, you have another problem which is you are passing values other than the ones you intend into printf. You are passing row and column, which are not the values at that location, but the numbers of the index. You want something like:
printf("%c",frame[row][column]);
As Paul Roub points out in comments, you are also doing some odd things with the way you are putting values into the array during your display loop, which is probably also going to confuse you if you develop this code further. First, you don't ever specify what is in the non-star parts of the array. Those should be set to something like the space character before, or at the same time, as adding stars. As written, the values will default to zero, which is unprintable null in ASCII, not space (which is 32).
Also, I assume you mean to be setting up the values first, and then displaying them. The way your loop works, it is setting the values as it draws them, in an interesting way that I would assume is not what you intend. Your example will currently end up showing what you expect, but usually I would expect you to fill in the values first and then display them later.

printf("%d%d",row,column); prints the row and column, not the value in frame[row][column].
#include <string.h>
#include <stdio.h>
int main(void) {
// Not clear if rowMax is the maximum index or the width. Assume maximum index.
size_t rowMax = 10;
size_t colMax = 5;
int star = '*';
// Much easier to use char array
char frame[rowMax + 1][colMax + 1]; // +1 the dimensions
// fill
memset(&frame[0], star, colMax + 1); // fill first row
for (size_t row = 1; row < rowMax; row++) {
memset(&frame[row], ' ', colMax); // fill with spaces
frame[row][colMax] = star;
}
memset(&frame[rowMax], star, colMax + 1); // fill last row
// print
for (size_t row = 0; row <= rowMax; row++) {
for (size_t col = 0; col <= colMax; col++) {
fputc(frame[row][col], stdout);
}
fputc('\n', stdout);
}
return 0;
}

Related

How to justify and print a paragraph using a 2d array in C?

I have an assignment that basically is asking to justify a paragraph given line length. So for instance the paragraph
"I am a student of C, this is my first assignment. I hope I finish on time." given line length of 17 should be as follows:
output
I am a student of
C, this is my
first assignment.
I hope I finish
on time.
I am having trouble with dynamically placing spacing in between the words. I currently have a function that counts the words in a paragraph and stores them into a 2d array but I have no idea how to a) calculate the amount of spacing in between words and b) how to dynamically print that justified paragraph.
Here is the code I have so far:
int getAllWordsFrom2DArray(char *paragraph, char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH]) {
int i,j,totalWords = 0;
for(i=0; i < strlen(paragraph); i++) {
int wordLength;
if (paragraph[i] == ' ' || paragraph[i+1] == '\0') {
totalWords++;
wordLength = i;
for(j=0; j < wordLength; j++) {
words[i][j] = paragraph[j];
}
}
}
printf("%s", words);
return totalWords;
}
//Code in progress
int getNumberOfWordsForNextLine(int totalWords, int lineLength, char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH]) {
int wordsForNextLine = 0;
for(int i=0; i < totalWords; i++) {
wordsForNextLine = 0 ;
}
}
//code in progress
void printNextLine(int wordsForNextLine) {
}
//skeleton code provided by instructor
void justifyAndPrintParagraph(char* paragraph, int lineLength) {
char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH];
int totalWords = getAllWordsFrom2DArray(paragraph, words);
int processedWords = 0;
while (processedWords < totalWords) {
int wordsForNextLine = getNumberOfWordsForNextLine(totalWords, lineLength, words);
printNextLine(wordsForNextLine);
processedWords += wordsForNextLine;
}
}
To clarify, we are not allowed to use strlok. Essentially we are expected to just use the basics in doing this. I need to use the void justifyAndPrintParagraph function and signature but other than that I'm free to do whatever.
Edit: I forgot to add that if spaces cannot be evenly divided then the extra spaces are to be allocated left to right.
Any help is greatly appreciated.
Consider how many spaces you have to distribute. For example, given the input:
18
I am the very model of a modern Major-General.
Computing the number of words that fit on the line goes:
"I" + "am" + "the" + "very" + (4-1 words) --> 13
"I" + "am" + "the" + "very" + "model" + (5-1 words) --> 19
So only the first 4 words fit on an 18-character line. The number of space characters to distribute are then easily calculated:
N = max_line_width - sum_of_word_lengths
Now for the hard part: how many spaces between each word? Your homework expects you to divvy extra unbalanced spaces left-to-right, meaning that each pair of words may have a different number of space characters.
However, the difference will always be a single space character. Take a moment to convince yourself this is true:
I···am···the··very
-2-4-6-8-0-2-4-6-8
In our little example, we find that there are three space characters in the first two inter-word spacings, and two space characters in the last.
The minimum number of space characters per inter-word spacing is easy enough to caluclate:
nsp = N / (number_of_words_in_line - 1)
Beware! What happens if you have only one word on the line? (Do you really need to distribute spaces for such a line?)
And now, for the cool tricky math part, you can calculate the number of times you need to add a space to the inter-word spacing as:
nplus1 = N - nsp * (number_of_words_in_line - 1)
or just:
nplus1 = N % (number_of_words_in_line - 1)
Keep in mind that it is possible that all inter-word spacings are the same number of space characters, and may be exactly one space character even. Notice how our calculations work just as well in those cases.
Now you can print the words for the line in a loop, adding nsp space characters after every word, plus an extra space after the first nplus1 words.
Remember, the last word of the line doesn’t get any spaces. It is followed by a newline!
Hopefully this should help you work your way through this assignment.
(I personally think it is a bit of a careless assignment as your first ever, introduction to C class.)
And now, if I have made errors, it is because I am very, very sleepy. Someone will surely point it out if I have.
So using Dúthomhas' suggestion I was able to create the function below:
void justifyAndPrintLine(char words[MAX_NUMBER_OF_WORDS][MAX_WORD_LENGTH], int processedWords, int amountOfWordsForNextLine, int lineLength) {
int total = 0;
for (int i = processedWords; i < processedWords + amountOfWordsForNextLine; i++) {
total += (int) strlen(words[i]);
}
int spaces = lineLength - total;
int spacesBetweenWords = spaces / (amountOfWordsForNextLine - 1);
int spacesRemaining = spaces % (amountOfWordsForNextLine - 1);
int spaceForThisWord;
int leftWords = processedWords + amountOfWordsForNextLine;
while (processedWords != leftWords) {
spaceForThisWord = spacesBetweenWords;
if (spacesRemaining > 0) {
spaceForThisWord++;
spacesRemaining--;
}
printLine(words[processedWords], spaceForThisWord);
processedWords++;
}
}
A key part of my understanding of the math was that the difference in spacing was always going to a single space character. Borrowing his math I was able to properly justify the paragraph. Thanks again Dúthomhas!

Printf multiple variable number of strings in C

I am writing a program in C that first prompts the user for an integer , then prints two strings: a blank space and a # on a variable number so that the result would be a right sided pyramid, like this:
#
##
###
####
#####
######
The problem i have resides in my for loop, here's what it looks like :
(n is the integer that the user prompts)
for (int i = 0 ; i < n ; i++)
{
printf("%c",n-1,' '); // printing the blank spaces gradually
printf("%c\n",i+2,'#'); // printing the hashes gradually
}
The idea is to print an decreasing number of spaces and an increasing number of hashes depending on the int.
P.S : Please consider helping me by saying what is wrong with my code, not giving me an actual new working one.
First, the problem with the code. It is based on an incorrect understanding of printf. printf cannot be used in the way desired in the code. Furthermore, even if did, it wont be printing spaces 'gradually' because you have fixed 'n-1'. You probably meant 'n-i' so it can gradually shrink.
Anyways, to fix:
There are a number of solutions, including rewriting with new logic. For your homework though, the code can still be 'fixed' by writing your own printf variant with desired functionality. e.g:
void mprintf(const char *fmt, int n, char c)
{
while (n--)
{
printf("%c", c);
}
}
And your code becomes:
for (int i = 0 ; i < n ; i++)
{
mprintf("%c",n-i,' '); // printing the blank spaces gradually
mprintf("%c",i,'#'); // printing the hashes gradually
printf("\n");
}
Extra credit:
Find out how you can simplify this code by removing certain useless thing.
You know every row has the same number of chars, counting the spaces and #, which is n. In the first row you have only one #, so n - 1 spaces, on the second you have 2 #'s, so n - 2 spaces, and so on. So you iterate from 0 to n - 1, and print a char every iteration, and you just have to keep count of how many chars you've already print. Start printing spaces and as soon as you have printed enough spaces, print a #. Code for it:
for (int i = 0 ; i < n ; i++)
{
int j = 0;
while (j < n)
{
if (j < n - i - 1)
printf(" ");
else
printf("#");
j++;
}
printf("\n");
}
You say:
Please consider helping me by saying what is wrong with my code, not giving me an actual new working one.
Ignoring cosmetic changes, your loop body is currently:
for (int i = 0; i < n; i++)
{
printf("%c", n-1, ' '); // printing the blank spaces gradually
printf("%c\n", i+2, '#'); // printing the hashes gradually
}
Problems include:
Too many arguments to the printf() calls.
%c requires a single argument, which is the character to be printed.
For n = 6, you will be printing Control-E rather than any blanks with the first print.
For the second print, you'll be printing Control-B through Control-G and no hashes.
You could use:
printf("%.*s", n - i - 1, " ");
to print a field of blanks of the appropriate width. You can't repeat a single character with printf(), though, so you'd have to use some other technique, such as a loop using putchar(), to print the appropriate number of hashes.
You should read, and re-read, and re-re-read the specification for printf(). I have to read it a couple of times a year to try and keep current; I usually find something new (or forgotten) on a given re-reading. Of course, I've only been coding in C for 30 years, and the specification has changed a few times over the years (and it hasn't gotten any simpler yet!), so it isn't very surprising.

Accounting for no existant characters as inputs C

Sorry if the question title is a little bit off, I had no idea what to call it just because it is such a peculiar question. What I am aiming to do is decode an input string encoded using a method I will explain in a bit, into a plain English text.
Encoding is done by choosing an integer nRows between 2 and half the length of the message, e.g. a message of length 11 would allow values of nRows in the range 2 to 5. The message is then written down the columns of a grid, one character in each grid cell, nRows in each column, until all message characters have been used. This may result in the last column being only partially filled. The message is then read out row-wise.
For example if the input message was ALL HAIL CAESAR, and the nRows value was 2, encoding would look like this:
A L H I A S R
L A L C E A #
Where # symbolizes a or blank character in the table, that doesn't actually exist - I have simply added it to explain the next part :)
The actual question I have is decoding these phrases. The code I have written thus far works for a few problems, but once the blank characters (#) become many the code begins to break down, as the code obviously does not register them and the algorithm skips past them.
My code is:
/*
* DeConfabulons.c
* A program to Decode for the Confabulons
*
* August 9th 2015
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
//A simple function confab which given input text encoded using
//the Confabulons encoding scheme, and a number of rows, returns
//the originally encoded phrase.
void deconfab(const char inText[], int nRows, char outText[])
{
int count = 0;
int i = 0;
int len = strlen(inText);
float help = ((float)len/(float)nRows);
int z = 0;
while (z < round(help))
{
while (((int)inText[count] > 0) && (count <= len))
{
outText[i] = inText[count];
i ++;
if (count < (int)help)
{
count = count + round((int)help+0.5);
}
else
{
float helper = count + help;
count = round(helper);
}
}
z ++;
count = z;
}
outText[i] = '\0';
}
Which thus far works for the Caesar example I gave earlier. The encoded form of it was ALHI ASRL ALCEA. The main(void) input I have been provided for that problem was:
char buffer[40] = {'\0'};
deconfab("ALHI ASRL ALCEA", 2, buffer);
printf("%s\n", buffer);
Which correctly outputs:
ALL HAIL CAESAR
However when working with cases with extra "blank" characters such as:
char buffer[60] = {0};
char* s = "Two hnvde eo frgqo .uxti hcjeku mlbparszo y";
deconfab(s, 13, buffer);
printf("%s\n", buffer);
The output should be:
The quick brown fox jumps over the lazy dog.
However my code will return:
Thdefq.the browneorouickmps ov g x julazy
I have concluded that this caused by the blank characters at the end in the last column by running through multiple tests by hand, however no matter what I try the code will not work for every test case. I am allowed to edit the bulk of the function in nearly any way, however any inputs or anything in int main(void) is not allowed to be edited.
I am simply looking for a way to have these blank characters recognized as characters without actually being there (as such) :)
First of all, as far as I see, you don't include those "null" characters in your input - if you did that (I guess) by adding any "dummy" characters, the algorithm would work. The reason it does in the first case is that the 'blank' character is missing at the end of the input - the same place as it's missing in the sentence.
You can try to make a workaround by guessing the length of a message with those dummy characters (I'm not sure how to formulate this) like:
ALHI ASRL ALCEA has 15 characters (15 mod 2 = 1) but ALHI ASRL ALCEA# has 16 characters. Similarly, Two hnvde eo frgqo .uxti hcjeku mlbparszo y has 44 characters (44 mod 13 = 5) so you need quite a lot of the dummy chars to make this work (13-5=8).
There are several ways at this point - you can for instance try to insert the missing blank spaces to align the columns, copy everything into a 2-dimensional array char by char, and then read it line by line, or just determine the (len mod rows) characters from the last column, remove them from the input (requires some fiddling with the classic C string functions so I won't give you the full answer here), read the rest and then append the characters from the last column.
I hope this helps.
There is some mess with index calculation.
At first it is pure discrete transformation. So, it should be implemented using only integer numbers.
The function below does what you need.
void deconfab(const char inText[], int nRows, char outText[])
{
int len = strlen(inText);
int cols = len / nRows;
int rows_with_large_cols = len % nRows;
int count = 0;
int col = 0;
int row = 0;
while (count < len)
{
int idx;
if (row < rows_with_large_cols)
idx = row * (cols + 1) + col;
else
idx = rows_with_large_cols * (cols + 1) +
(row - rows_with_large_cols) * cols + col;
if (idx > len - 1) {
++col;
row = 0;
idx = col;
}
outText[count] = inText[idx];
++row;
++count;
}
outText[count] = '\0';
}
It may be rewritten more nicely. Now it is like a pseudocode to explain the algorithm.
You cannot use the standard str* functions if you are going to handle nulls. You must, instead, work with the data directly and use the *read family of functions to get your data.

Getting the size of my array

I am trying to get the size of my array but am having no luck...
I've read from various other threads that the way to grab the size of an array is:
theSize = (sizeof(array) / sizeof(array[0]))
But that seems to grab the empty elements of the array too.
How would we grab just the elements that are used up... for example:
char array[200][40];
for (i = 1; i < (sizeof(array) / sizeof(array[0])); i++) {
printf("%s", array[i-1]);
The output for an array that used 3 of its 200 elements would be...
First
Second
Third
(This is where it should stop, however it gives a bunch of question marks,
so I assume I'm grabbing memory i'm not supposed to use.
Note: I want it so that i < 3 for the loop (since the array has 3 elements used up)
There are two ways to do this.
The first way is to keep track of how many elements are used in a separate variable. Note that you must ensure that used is always less than of equal to the size of the array.
char array[200][40];
size_t used = 3;
for (int i = 0; i < used; ++i) {
printf("%s", array[i]);
}
The second way is to flag the first unused element with a special value, such as 0, and output all values until the flagged one. In your case, it would be natural to mark the end of the array with an empty string.
char array[200][40];
size_t size = sizeof(array) / sizeof(array[0]);
for (int i = 0; i < size && array[i][0] != 0; ++i) {
printf("%s", array[i]);
}

keep getting ascii value where char is expected

When a coordinate is selected, it should be replaced with a "~". However, it's being replaced with the ascii value for the ~ instead (126). I tried a few different things, but I always get the 126 instead of the ~. Any ideas?
Thanks for the help!
int board_is_empty(int N, int board[ROWS][COLS])
{
int i = 0, j = 0;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
if (board[i][j] != '~')
{
return 0;
}
}
}
return 1;
}
//updates the board to replace each selected coordinate with a ~.
//returns nothing
void update_board (int board[ROWS][COLS], int row_target, int column_target)
{
board[row_target][column_target] = '~';
}
int main(void)
{
int game_board[ROWS][COLS] = {0};
int rows, columns = 0;
int players_turn = 1, target_column = -1, target_row = -1, value = 0;
int row_selection = 0, column_selection = 0;
int i = 0;
initialize_game_board(game_board);
display_board(game_board);
generate_starting_point(game_board, &rows, &columns);
printf ("\nPlease hit <Enter> to continue.\n");
getchar ();
while (board_is_empty(ROWS, game_board) != 1)
{
select_target (&target_row, &target_column, players_turn);
value += game_board[target_row][target_column];
update_board (game_board, target_row, target_column); //should cause the coordinates at target_row && target_column to be replaced with a ~
display_board(game_board);
}
printf("\n%d", value);
}
'~' is a character and you have declared board as a two dimensional integer array.
so when you write board[row_target][column_target] = '~';
it convert '~' it into integer i.e into its ascii value which is 126
and there for it becomes board[row_target][column_target] = 126
I will suggest make board as two dimensional character array. Hopefully it will solve your problem.
And in case if you want it as integer only then consider 126 as a special no which means '~' by declaring
For storing your coordinates, you are using an integer array. When you execute
board[row_target][column_target] = '~'; tilde's ascii value (126) is assigned to LHS. There is no way you can assign a character to an integer value. I think you should use some special number rather than tilde. If I were you, I would use INT_MIN or INT_MAX.
There isn't a difference between the character '~' and the number 126 as far as the C language is concerned, '~' == 126.
(You used "~" which i would normally use for a string, but i assume you don't actually mean that).
If you want to display a value, you have to use the correct format string. %d is for decimal integers, %c would be for characters (the variable holding the value should also be a char)
In C, chars are just integers. At output time they are represented as characters but internally they hold just the ASCII code of that character.
Since your board is a matrix of int's, when you assign '~' you are effectively assigning the number 126 to a position of the board. If you check that position, the expected result is to get an int equal to 126.
However, if you want to see that value as a character, you can do it by casting that number into a char:
printf("%c", value);
Take a look:
#include <stdio.h>
int main()
{
int i = '~';
char c = '~';
printf("Integer: %d\n", i); /* outputs: 126 */
printf("Char: %c\n", c); /* outputs: ~ */
printf("Integer casted to char: %c\n", i); /* outputs: ~ */
}
That is, your value is right. You just need to get the representation you want. (If you want to be able to store the value 126 in the board and the character ~ at the same time, then you're out of luck because for C they are the same thing -you can use some other value that you know that the board isn't going to hold, like -1 or something like that).
Update:
So, if I didn't get it wrong what you're trying to do is to read numbers from a bidimensional matrix of random integers and mark each one as you go reading them.
If that is what you're trying to achieve, then your idea of using '~' to mark the read positions isn't going to work. What I meant before is that, in C, 126 and the character '~' are the exact same thing. Thus, you won't be able to differentiate those positions in which you have written a '~' character and those ones in which a random 126 is stored by chance.
If you happen to be storing positive integers in your array, then use -1 instead of '~'. That will tell you if the position has been read or not.
If you are storing any possible random integer, then there is nothing you can store in that array that you can use to mark a position as read. In this case a possible solution is to define your array like this:
typedef struct {
int value;
char marked;
} Position;
Position board[ROWS][COLS];
Thus, for each position you can store a value like this:
board[row][col].value = 23123;
And you can mark it as read like this:
board[row][col].marked = 'y';
Just, don't forget to mark the positions as not read (board[row][col].marked = 'n';) while you fill the matrix with random integers.

Resources