Storing input into a character array

B

Bert

Hi, I'm unhappy: why doesn't this work?

char enc[10000];
char temp[70];

for(int i=0;i<10000;i++){
fscanf(in,"%s",&temp);

if(temp[0]=='#')break;
else
for(int j=0;j<70;j++)
if(temp[j]!='\0')
enc=temp[j];
else break;
}

The input is from a text file (.txt) that contains an encrypted
message between 1 and 10 000 letters long that may be split across
several lines in the input file; each line will contain between 1 and
70 letters inclusive and the final line will contain one #. I want the
entire message to be stored in enc (excluding the #). I thought I'm
using temp to store one line of text, checking if the first character
is a # and if not storing those characters into the next available
slots in the array enc until enc is filled up.

I'm unhappy
Bert
 
B

badc0de4

Bert said:
Hi, I'm unhappy: why doesn't this work?

char enc[10000];
char temp[70];

for(int i=0;i<10000;i++){
fscanf(in,"%s",&temp);

if(temp[0]=='#')break;
else
for(int j=0;j<70;j++)
if(temp[j]!='\0')
enc=temp[j];
else break;
}

The input is from a text file (.txt) that contains an encrypted
message between 1 and 10 000 letters long that may be split across
several lines in the input file; each line will contain between 1 and
70 letters inclusive and the final line will contain one #. I want the
entire message to be stored in enc (excluding the #). I thought I'm
using temp to store one line of text, checking if the first character
is a # and if not storing those characters into the next available
slots in the array enc until enc is filled up.

I'm unhappy
Bert
 
B

badc0de4

Bert said:
Hi, I'm unhappy: why doesn't this work?

char enc[10000];
char temp[70];

for(int i=0;i<10000;i++){
fscanf(in,"%s",&temp);

if(temp[0]=='#')break;
else
for(int j=0;j<70;j++)
if(temp[j]!='\0')
enc=temp[j];


You're not updating i.
You're writing multiple times to the same location.
 
B

Bert

...firstly, you're not protecting your buffer against
inputs longer than 69 characters. Fix that with %69s rather than %s.
I don't need to protect my buffer. This question to be solved just
needs to be solved and not worrying about crashing. Judges want to see
the program work according to the question they've written, not to see
if it is secure code.
Secondly, you're not capturing the return from fscanf to check that the
input succeeded. Fix that with a comparison against 1 (the number of
fields you want to parse).
My comment would be similar to that of above.
Thirdly, you're using &temp rather than temp -
since temp is (in this context) treated as if it were a pointer to the
first byte in the temp array, the ampersand is not required. Thanks

Fourthly, your parse will stop at the first space, which probably isn't what you
want. To fix that, use fgets rather than fscanf.
Why will my parse stop at the first space and how does fgets work
differently to fscanf?
Fifthly, your parse will fail if the encrypted data you're reading contains a character that your
input routine treats as a sentinel (e.g. newline for fgets), but which is
intended to be part of the data feed. Fix that, if necessary, by reading
fixed-size blocks of input into a buffer (e.g. using fread instead of
fgets) and parse it for the '#' yourself, using e.g. memchr.
The encrypted message will never have spaces nor punctuation in it no
matter how long it ends up being.

Now I'm fairly unhappy
Bert
 
K

Keith Thompson

Bert said:
Why will my parse stop at the first space and how does fgets work
differently to fscanf?

Because that's what fscanf's "%s" option is defined to do.

Surely you have some reference book that documents all this stuff.
 
B

Bert

I've changed the code and it now is:

for(int i=0;i<10000;i++){
fgets(in,"%s",temp);

if(temp[0]=='#'){break;
} else {
for(int j=0;j<70;j++)
if(temp[j]!='\0'){
enc=temp[j];
}
else{
break;
}
}
}

Now it doesn't compile.
Can someone please write out what it's supposed to be? I've tried two,
three ways (this is my third attempt) to do this but I can't do it. I
find input so much harder without the string type like in C#.
If you don't write out what it's supposed to be can you write out the
code in pseudocode?
I can store an integer input easily:
fscanf(in,"%d",&rows);
but I can't get this encrypted message working.
I really want to get on to the decryption part of this question yet
I've spent DAYS trying to figure out how to store text input into a
char array and it's a really bad feeling.
My pseudocode was:

Have a counter var. for enc's elements
for(int i=0;i<10000;i++)
Get the next line of the enc. msg - store in temp[]
If the first element of the array (the first character of the
current line's input) is a #, break out of loop.
Else assign the temp[] contents in to enc[]
for(int j=0;j<70;j++)
if(temp[j]!='\0')
enc=temp[j];
else break;
 
H

Herbert Rosenau

Hi, I'm unhappy: why doesn't this work?

char enc[10000];
char temp[70];

for(int i=0;i<10000;i++){
fscanf(in,"%s",&temp);

if(temp[0]=='#')break;
else
for(int j=0;j<70;j++)
if(temp[j]!='\0')
enc=temp[j];
else break;
}

The input is from a text file (.txt) that contains an encrypted
message between 1 and 10 000 letters long that may be split across
several lines in the input file; each line will contain between 1 and
70 letters inclusive and the final line will contain one #. I want the
entire message to be stored in enc (excluding the #). I thought I'm
using temp to store one line of text, checking if the first character
is a # and if not storing those characters into the next available
slots in the array enc until enc is filled up.


Beside all that that Richard said already you ignores
- read errors
- EOF, the fact that the file may go out of chars before 10000th char
is readed.
- 10000 chars are commonly unequal to 10000 lines you tries to read.

So you're using a unsuitable function to get your problem resolved.

Your problem is
.. read the file char by char until any char is readed, that is EOF
instead of a char you want shows up
- when the first char of a new line is '#' stop further reading
looks like you means only 'ignore this line' instead of ignore the
whole remaining file

Doing it right you'll be able to encode on the fly instead to use the
wrong and oversized function and copying chars wrongly around.

Hints:
- '\n' tells you that you've readed a whole line completely
- EOF tells you that gthere is no char left in the file
- getc/getchar() returns int, not char


--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2R Deutsch ist da!
 
S

santosh

Bert said:
On Jun 29, 4:09 pm, Richard Heathfield <[email protected]> wrote:

[see OP for problem statement]
I don't need to protect my buffer. This question to be solved just
needs to be solved and not worrying about crashing. Judges want to see
the program work according to the question they've written, not to see
if it is secure code.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
unsigned char *message;
unsigned int msg_length, ctr;
FILE *msg_file;

/* open file containing message */
msg_file = fopen(argv[1], "r");
/* calculate the bytes the file contains */
for (msg_length = 0; fgetc(msg_file) != EOF; msg_length++);
/* adjust for the #EOL on the final line */
msg_length -= 2;
/* allocate an array of sufficient space */
message = malloc(msg_length);
/* read file into array */
rewind(msg_file);
for (ctr = 0; ctr < msg_length; ctr++)
message[ctr] = fgetc(msg_file);
/* print what we have read */
for (ctr = 0; ctr < msg_length; ctr++)
putc(message[ctr], stdout);
fclose(msg_file);
free(message);
return 0;
}

Hope this helps.
 
C

Chad

pete said:
Bert said:
Hi, I'm unhappy: why doesn't this work?
char enc[10000];
char temp[70];
for(int i=0;i<10000;i++){
    fscanf(in,"%s",&temp);
    if(temp[0]=='#')break;
    else
        for(int j=0;j<70;j++)
            if(temp[j]!='\0')
                enc=temp[j];
            else break;
}
The input is from a text file (.txt) that contains an encrypted
message between 1 and 10 000 letters long that may be split across
several lines in the input file; each line will contain between 1 and
70 letters inclusive and the final line will contain one #. I want the
entire message to be stored in enc (excluding the #). I thought I'm
using temp to store one line of text, checking if the first character
is a # and if not storing those characters into the next available
slots in the array enc until enc is filled up.
I'm unhappy

char enc[10000];
int i, rc;
for(i = 0; 10000 > i; ++i) {
    rc = getc(in);
    if (rc == EOF || rc == '#') {
        break;
    }
    enc = rc;
}


If you don't want newline characters in your array,
which I think is the case:

char enc[10000];
int rc;
int i = 0;

while (10000 > i) {
     rc = getc(in);
     if (rc == EOF || rc == '#') {
         break;
     }
     if (rc != '\n') {
         enc[i++] = rc;
     }

}


But the OP wanted input up to 70 characters. I don't see how your
solution accounts for this.


Chad
 
K

Keith Thompson

Bert said:
I've changed the code and it now is:

for(int i=0;i<10000;i++){
fgets(in,"%s",temp);

if(temp[0]=='#'){break;
} else {
for(int j=0;j<70;j++)
if(temp[j]!='\0'){
enc=temp[j];
}
else{
break;
}
}
}

Now it doesn't compile.

[...]

It would be helpful if you'd tell us *how* it doesn't compile
(copy-and-paste the exact message you're getting from your compiler).
Without a complete program, we can't be sure what all the problems
are.

In the meantime, take a look at the line:

fgets(in,"%s",temp);

Why are you passing a format string to fgets? Read the documentation
for the fgets function, and pass it the arguments it's expecting.
 
B

Bert

pete said:
Bert said:
Hi, I'm unhappy: why doesn't this work?
char enc[10000];
char temp[70];
for(int i=0;i<10000;i++){
fscanf(in,"%s",&temp);
if(temp[0]=='#')break;
else
for(int j=0;j<70;j++)
if(temp[j]!='\0')
enc=temp[j];
else break;
}
The input is from a text file (.txt) that contains an encrypted
message between 1 and 10 000 letters long that may be split across
several lines in the input file; each line will contain between 1 and
70 letters inclusive and the final line will contain one #. I want the
entire message to be stored in enc (excluding the #). I thought I'm
using temp to store one line of text, checking if the first character
is a # and if not storing those characters into the next available
slots in the array enc until enc is filled up.
I'm unhappy

char enc[10000];
int i, rc;
for(i = 0; 10000 > i; ++i) {
rc = getc(in);
if (rc == EOF || rc == '#') {
break;
}
enc = rc;
}


If you don't want newline characters in your array,
which I think is the case:

char enc[10000];
int rc;
int i = 0;

while (10000 > i) {
rc = getc(in);
if (rc == EOF || rc == '#') {
break;
}
if (rc != '\n') {
enc[i++] = rc;
}

}


Thanks, that's just what I needed.

Now the first part of this output from the code below is given
correctly but there are strange symbols appearing after that in
command prompt.

char rows[numrows][100];
int j = 0;
for (int k=0; k<i; k+=(numrows*2-2)) {
rows[0][j] = enc[k];
++j;
}
As in my OP, this program is intended to decrypt messages and here is
PART of the decryption. If the input indicates 4 rows (different rows
means that the message has been ENcrypted differently) I want the
computer to take every sixth letter of the string in enc and store it
in the rows.
From an input I've tested with enc having 24 letters and 4 rows
encryption, it does correctly output the 4 characters of the first row
(the exact number of characters wanted in the right order; this output
is SOLELY what I wanted) correctly but is followed by symbols such as
an up arrow and @ etc.
 
B

Bert

Why is it that from the input of

3
COPATGAHRRY
#

(in zigin.txt)

that the Y at the end of the encrypted message above isn't outputted
from the following program:

#include <stdio.h>

main()
{
/********************************/
FILE* in=fopen("zigin.txt","r");
char enc[10000];

int numrows, temp;
int numletters = 0;

fscanf(in,"%d",&numrows);

while (10000 > numletters)
{
temp = getc(in);

if (temp == EOF || temp == '#')
{
break;
}

if (temp != '\n') {
enc[numletters++] = temp;
}
}
/*********************************/

char row1[numletters/numrows];
char lastrow[numletters/numrows];

char midrows[numrows-2][numletters/numrows+2];


int nlt_inarrays = 0;
/**/
for (int i = 0; i < (numletters/numrows); i++)
{
row1 = enc[nlt_inarrays];
++nlt_inarrays;
}


int remaining_letters = numletters % numrows - 3;
int nmidrowswithvalues=0;
for (int i = 0; i < remaining_letters; i++)
{
for (int j = 0; j < (numletters/numrows + 2); j++)
{
midrows[j] = enc[nlt_inarrays];
++nlt_inarrays;
}
++nmidrowswithvalues;
}

for (int i = 0; i < (numrows-2-nmidrowswithvalues); i++)
{
for (int j = 0; j < (numletters/numrows + 1); j++)
{
midrows[i+nmidrowswithvalues][j] = enc[nlt_inarrays];
++nlt_inarrays;
}
}


for (int i = 0; i < (numletters/numrows); i++)
{
lastrow = enc[nlt_inarrays];
++nlt_inarrays;
}
/**/


printf("row1 ");
for (int i = 0; i < (numletters/numrows); i++)
{
printf("%c", row1);
}
printf("\n");


for (int i = 0; i < remaining_letters; i++)
{
for (int j = 0; j < (numletters/numrows + 2); j++)
{
printf("%c", midrows[j]);
}
printf("\n");
}

for (int i = 0; i < (numrows-2-nmidrowswithvalues); i++)
{
for (int j = 0; j < (numletters/numrows + 1); j++)
{
printf("%c", midrows[i+nmidrowswithvalues][j]);
}
printf("\n");
}

printf("Last row ");
for (int i = 0; i < (numletters/numrows); i++)
{
printf("%c", lastrow);
}
}

I'm annoyed
Bert
 
B

Ben Bacarisse

Bert said:
Why is it that from the input of

3
COPATGAHRRY
#

(in zigin.txt)

that the Y at the end of the encrypted message above isn't outputted
from the following program:

It is almost impossible to answers that sort of question. At one
level it is obvious -- the loop that outputs the last row runs three
times from i == 0 while i < 3 (3 is numletters/numrows) -- so it can't
print more than the 3 letters you see "HRR". You can't change the
loop bounds because that (3) is the size of the array you've made.

The trouble I have is that I can't work out what should be happening.
It would help if there were a description of what the program should
do.
 
E

Edward A. Falk

I don't need to protect my buffer. This question to be solved just
needs to be solved and not worrying about crashing. Judges want to see
the program work according to the question they've written, not to see
if it is secure code.

Ahh, you didn't mention that this is a contest and you only want it good
enough to be judged. Or maybe I missed it.

No matter, you should get in the habit of writing correct code from
the get-go, even if the judges don't need it to be really correct.
And besides, I bet style counts for something in this contest, and a
program that checks for errors will score better than one that doesn't.

Anyway, a couple of general issues:

As mentioned elsewhere, if "temp[]" is an array, then "temp" is treated
as a pointer to the start of the array, and you should use it instead of
"&temp" which is meaningless as far as I know.

fscanf() is not nearly as useful as you think it is. As you've already
discovered, %s isn't doing what you thought it would do, but more
importantly, fscanf() is rather squirrely about line endings. It's hard
work to get it right. In general, you want to do fgets() into a buffer,
followed by sscanf() on that buffer. Since you're already using a buffer
anyway, this is no real burden.

Please, please, please get in the habit of checking array bounds and
return codes even if it's just a contest and it doesn't matter. 90%
of the security problems on the internet are caused by programmers who
didn't do these simple things.

Along those lines, you should almost never use sprintf(); use snprintf()
instead. The same is true for any other function that manipulate strings
unless you absolutely, positively trust your source. Likewise, your %s
should have been a %69s as mentioned elsewhere.
 
K

Keith Thompson

As mentioned elsewhere, if "temp[]" is an array, then "temp" is treated
as a pointer to the start of the array, and you should use it instead of
"&temp" which is meaningless as far as I know.

If temp is an array, then the name temp as an expression is implicitly
converted to a pointer to the array's first element in most, but not
all, contexts. "&temp" is certainly not meaningless; it yields the
address of the array object (which is of a different type than the
address of its first element). See section 6 of the comp.lang.c FAQ
for details.
fscanf() is not nearly as useful as you think it is. As you've already
discovered, %s isn't doing what you thought it would do, but more
importantly, fscanf() is rather squirrely about line endings. It's hard
work to get it right. In general, you want to do fgets() into a buffer,
followed by sscanf() on that buffer. Since you're already using a buffer
anyway, this is no real burden.

Note that sscanf can have problems with numeric data; there's no good
way to handle overflow.

[...]
Along those lines, you should almost never use sprintf(); use snprintf()
instead. The same is true for any other function that manipulate strings
unless you absolutely, positively trust your source. Likewise, your %s
should have been a %69s as mentioned elsewhere.

snprintf() isn't always available; it's new in C99, and most C
implementations don't fully support the C99 standard. sprintf() can
be used safely if you're careful (you have to make sure the target
array is big enough for any possible data).
 
B

Barry Schwarz

Why is it that from the input of

3
COPATGAHRRY
#

(in zigin.txt)

that the Y at the end of the encrypted message above isn't outputted
from the following program:

Because after detecting the '#' your program only processes the first
ten letters.

By the way, you ought to fclose the file also.
#include <stdio.h>

main()
{
/********************************/
FILE* in=fopen("zigin.txt","r");
char enc[10000];

int numrows, temp;
int numletters = 0;

fscanf(in,"%d",&numrows);

while (10000 > numletters)
{
temp = getc(in);

if (temp == EOF || temp == '#')
{
break;
}

if (temp != '\n') {
enc[numletters++] = temp;
}
}
/*********************************/

char row1[numletters/numrows];
char lastrow[numletters/numrows];

char midrows[numrows-2][numletters/numrows+2];


int nlt_inarrays = 0;
/**/
for (int i = 0; i < (numletters/numrows); i++)
{
row1 = enc[nlt_inarrays];


You store the first three letters (COP) in row1.
++nlt_inarrays;
}


int remaining_letters = numletters % numrows - 3;

This evaluates to -1.
int nmidrowswithvalues=0;
for (int i = 0; i < remaining_letters; i++)

This loop never executes.
{
for (int j = 0; j < (numletters/numrows + 2); j++)
{
midrows[j] = enc[nlt_inarrays];
++nlt_inarrays;
}
++nmidrowswithvalues;
}

for (int i = 0; i < (numrows-2-nmidrowswithvalues); i++)
{
for (int j = 0; j < (numletters/numrows + 1); j++)
{
midrows[i+nmidrowswithvalues][j] = enc[nlt_inarrays];


You store the next 4 letters (ATGA) in midrows[0], even though you
allocated room for 5.
++nlt_inarrays;
}
}


for (int i = 0; i < (numletters/numrows); i++)
{
lastrow = enc[nlt_inarrays];


You store the next 3 letters (HRR) in lastrow.
++nlt_inarrays;
}
/**/


printf("row1 ");
for (int i = 0; i < (numletters/numrows); i++)
{
printf("%c", row1);
}
printf("\n");


for (int i = 0; i < remaining_letters; i++)
{
for (int j = 0; j < (numletters/numrows + 2); j++)
{
printf("%c", midrows[j]);
}
printf("\n");
}

for (int i = 0; i < (numrows-2-nmidrowswithvalues); i++)
{
for (int j = 0; j < (numletters/numrows + 1); j++)
{
printf("%c", midrows[i+nmidrowswithvalues][j]);
}
printf("\n");
}

printf("Last row ");
for (int i = 0; i < (numletters/numrows); i++)
{
printf("%c", lastrow);
}
}


You print out 3 + 4 + 3 = 10 letters but your data contained 11.
I'm annoyed
Bert


Remove del for email
 
C

Chad

Why is it that from the input of

(in zigin.txt)
that the Y at the end of the encrypted message above isn't outputted
from the following program:

Because after detecting the '#' your program only processes the first
ten letters.

By the way, you ought to fclose the file also.






#include <stdio.h>
main()
{
   /********************************/
   FILE* in=fopen("zigin.txt","r");
   char enc[10000];
   int numrows, temp;
   int numletters = 0;
   fscanf(in,"%d",&numrows);
   while (10000 > numletters)
   {
       temp = getc(in);
       if (temp == EOF || temp == '#')
       {
           break;
       }
       if (temp != '\n') {
           enc[numletters++] = temp;
       }
   }
   /*********************************/
   char row1[numletters/numrows];
   char lastrow[numletters/numrows];
   char midrows[numrows-2][numletters/numrows+2];
   int nlt_inarrays = 0;
   /**/
   for (int i = 0; i < (numletters/numrows); i++)
   {
       row1 = enc[nlt_inarrays];


You store the first three letters (COP) in row1.
       ++nlt_inarrays;
   }
   int remaining_letters = numletters % numrows - 3;

This evaluates to -1.


How do you arrrive at -1 when there doesn't appear to be a value for
'numrows'?
This loop never executes.

And while I'm having a brainlapse, how do you figure the loop never
executes?

Chad
 
B

Barry Schwarz

Why is it that from the input of

(in zigin.txt)
that the Y at the end of the encrypted message above isn't outputted
from the following program:

Because after detecting the '#' your program only processes the first
ten letters.

By the way, you ought to fclose the file also.






#include <stdio.h>
main()
{
   /********************************/
   FILE* in=fopen("zigin.txt","r");
   char enc[10000];
   int numrows, temp;
   int numletters = 0;
   fscanf(in,"%d",&numrows);
   while (10000 > numletters)
   {
       temp = getc(in);
       if (temp == EOF || temp == '#')
       {
           break;
       }
       if (temp != '\n') {
           enc[numletters++] = temp;
       }
   }
   /*********************************/
   char row1[numletters/numrows];
   char lastrow[numletters/numrows];
   char midrows[numrows-2][numletters/numrows+2];
   int nlt_inarrays = 0;
   /**/
   for (int i = 0; i < (numletters/numrows); i++)
   {
       row1 = enc[nlt_inarrays];


You store the first three letters (COP) in row1.
       ++nlt_inarrays;
   }
   int remaining_letters = numletters % numrows - 3;

This evaluates to -1.


How do you arrrive at -1 when there doesn't appear to be a value for
'numrows'?


Look at the first executable statement in the function, the one that
calls fscanf.
And while I'm having a brainlapse, how do you figure the loop never
executes?

i is 0. remaining_letters is -1. i < remaining_letters evaluates to
false. The loop terminates before the first iteration.

Don't feel bad, it's Monday and we understand.


Remove del for email
 
B

Bert

ZIGZAG CIPHER
Input File: zigin.txt Output File: zigout.txt Time Limit: 1 second
The latest development in cryptography, certain to be adopted by the
military, governments and anyone else who is paranoid, is the zig-zag
cipher.
To encrypt a message using the zig-zag cipher, the letters of the
message are written on the page in a zig-zag pattern. This is
illustrated below for the message "CARTOGRAPHY".

C O P
A T G A H
R R Y
The letters are then read one row at a time, from the top row to the
bottom. In the diagram above, the first row spells "COP", the second
spells "ATGAH" and the third spells "RRY". Finally, these are combined
to obtain the final encrypted message, which is "COPATGAHRRY".
The zig-zag cipher can be extended to use as many rows as you like.
For instance, using a zig-zag cipher with six rows, the message
"CHARLIETHEWONDERBUDGIE" is encrypted to become
"CWIHEOGEAHNDRTDULEEBIR" as seen in the following diagram.
C W I
H E O G E
A H N D
R T D U
L E E B
I R
Your task is to write a program that can decrypt messages written in
the zig-zag cipher. Your program must read the number of rows used in
the cipher as well as an encrypted message, and must output the
original (decrypted) message.
Input
The first line of input will consist of a single integer r, the number
of rows used in the zigzag cipher (2 <= r <= 100).
Following this will be the encrypted message. The encrypted message
will consist entirely of upper-case letters, with no spaces or
punctuation. This message may be split across several lines in the
input file; each line will contain between 1 and 70 letters inclusive.
The entire encrypted message will be between 1 and 10 000 letters
long.
Following the encrypted message will be a final line containing a
single hash (#).
Output
Your output should consist of a single line containing the entire
decrypted message (note that this line might be very long). The output
line should contain no spaces or punctuation.
Sample Input 1 Sample Output 1
3 CARTOGRAPHY
COPATGAHHRY
#
Sample Input 2 Sample Output 2
6 CHARLIETHEWONDERBUDGIE
CWIHEOGE
AHNDRTDU
LEEBIR
#
Scoring
The score for each input file will be 100% if the correct decrypted
message is written to the output file and 0% otherwise.

Excluding the 'storing input into a character array' part, I've
written the code by myself to sort the encrypted message into the
first row, (total number of rows - 2) middle rows and the last row. As
far as I've tested, my program (so far) does that ALWAYS correctly.
What I've given up on is how to fetch the right element of the right
row array in the right order and regurgitate it into zigout.txt. I can
do it by pen and paper, but I can't tell the computer how to do this.
Like, it's just beyond me how people and their creativity work out the
loop to do this and how they planned their code for doing that all out
before they started writing the code in C and how they check that it's
correct and what they're thought processes are and all the rest of it.

l means letter/s
n means number/s
enc and dec end with rypted
msg means message
curr means current
m means middle

#include <stdio.h>

main()
{
FILE* in=fopen("zigin.txt","r");
char enc[10000];

int nrows, temp;
int nlmsg = 0;

fscanf(in,"%d",&nrows);

while (10000 > nlmsg)
{
temp = getc(in);

if (temp == EOF || temp == '#')
{
break;
}

if (temp != '\n') {
enc[nlmsg++] = temp;
}
}

int nlfrow = (nlmsg + nrows * 2 - 3) / (2 * (nrows - 1) );
int nllrow = (nlmsg + nrows - 2) / (2 * (nrows - 1) );
int nmrows = nrows - 2;
int nlm = nlmsg - nllrow - nlfrow;
int lleft = nlmsg - nllrow - 1;
int nthletter = nlfrow;
char frow[nlfrow];
char mrow[nmrows][5050];
char lrow[nllrow];

for (int i = 0; i < nlfrow; i++)
{
frow = enc;
}

if (nlfrow == nllrow + 1)
{
for (; (nmrows - 1) >= 0; nmrows--)
{
int nlcurrow = nlm / nmrows;

if ( ( (nlcurrow + 1) * nmrows) == nlm)
{
++nlcurrow;
}

for (; (nlcurrow - 1) >= 0; nlcurrow--)
{
mrow[nmrows - 1][nlcurrow - 1] = enc[lleft];
--lleft;
--nlm;
}
}
}
else
{
for (int i = 1; i <= nmrows; i++)
{
int nlcurrow = nlm / nmrows;

if ( ( (nlcurrow + 1) * nmrows ) == nlm)
{
++nlcurrow;
}

for (int j = 1; j <= nlcurrow; j++)
{
mrow[i-1][nlcurrow-1] = enc[nthletter];
++nthletter;
--nlm;
}
}
}

nlfrow = (nlmsg + nrows * 2 - 3) / (2 * (nrows - 1) );
nlm = nlmsg - nllrow - nlfrow;
for (int i = 0; i < nllrow; i++)
{
lrow = enc[nlfrow+nlm+i];
}
}


return I_GAVE_UP;
 
B

Ben Bacarisse

Bert said:
ZIGZAG CIPHER
Input File: zigin.txt Output File: zigout.txt Time Limit: 1 second
The latest development in cryptography, certain to be adopted by the
military, governments and anyone else who is paranoid, is the zig-zag
cipher.
To encrypt a message using the zig-zag cipher, the letters of the
message are written on the page in a zig-zag pattern. This is
illustrated below for the message "CARTOGRAPHY".

C O P
A T G A H
R R Y
The letters are then read one row at a time, from the top row to the
bottom. In the diagram above, the first row spells "COP", the second
spells "ATGAH" and the third spells "RRY". Finally, these are combined
to obtain the final encrypted message, which is "COPATGAHRRY".

Quite a neat exercise...

Excluding the 'storing input into a character array' part, I've
written the code by myself to sort the encrypted message into the
first row, (total number of rows - 2) middle rows and the last row. As
far as I've tested, my program (so far) does that ALWAYS correctly.
What I've given up on is how to fetch the right element of the right
row array in the right order and regurgitate it into zigout.txt.

I think you are going about this the wrong way. There is no need to
store the rows. Even if you do, you have then (as you have found out)
the problem of walking the rows in the right pattern. Even if you did
want to use arrays for the rows, I think it is a mistake to make the
top and bottom rows separate. The more uniform the data structure,
the simpler the program usually is.
I can
do it by pen and paper, but I can't tell the computer how to do this.

The pen and paper reinforce the "rows" idea which suggest spreading
the input out and gathering it up. As I say, I think that is the
wrong way.

Try this hint. Write it as a plain loop over the input (you need to
store the input because you need the length in advance but that is
all you need to store it for[1]):

while (i < length) {
...
output[x] = input[i++];
...
}

Your program will process the input from left to right, setting the
output positions like this:

0 1 2 3 4 5 6 7 8 9 10
C O P A T G A H R R Y

0 C
1 O
2 P
3 A
4 T
5 G
6 A
7 H
8 R
9 R
10 Y

In other words, you need to generate the sequence 0, 4, 8, 1, 3, 5, 7,
9, 2, 6, 10 in the variable I wrote as x. If found the second longer
case (that I snipped) more useful in seeing the pattern for generating
the sequence of target indexes. See if you can see how the rows of
the zigzag produce the skipping about needed to put the next character
in the right output slot.

Of course, this may not help, but it is the way I did it and the
solution is not too complex when seen this way.

I will post my solution soon, since it is "cutesy" enough that I
double you could hand it in and get away with it. I ignored the daft
input specification that seems to date from another era, but I suppose
you have to follow it[1].

[1] If the encoder produced, as output, the number of rows used, the
length of the input and then the data, the decoder could work without
storing the input at all.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top