In addition to, and in agreement with, the other answer, there are fundamentals you are missing.
When you get into encodeChar
, what parameter are you using to tell you how many elements table
has? (you do want to iterate over each element in table
checking table[i].source
against each character to determine if a substitution is needed, right?)
note: C generally uses all lowercase for variable and function names while reserving all uppercase for constants and macros. C avoids the use of camelCase and MixedCase names -- leave those for C++ or java. While it is a matter of style, so it is largely up to you, it does say a lot about your appreciation for C, just like using gets
does....
Don't use magic numbers in your code. If you need a constant, (e.g. 80
), declare one at the top of your code, e.g.
#define MAXC 80 /* maximum characters for input buffer */
If you have multiple constants to declare, using an enum
is an orderly way to declare global constants.
Using constants prevents having to pick through multiple array declarations to change their size. There is one convenient place up top to make the change.
Don't use gets
, it is helpless against buffer overrun and has been removed from C11. Use fgets
. All valid line-oriented input functions (e.g. fgets
, and POSIX getline
) read and include the trailing '\n'
in the buffers they fill with input. Therefore, you need to trim the trailing newline from input, or you will have '\n'
dangling off the end of any string you store that can cause problems with comparisons, etc.. Simply get the length and check character length - 1
to validate it is a '\n'
, then just overwrite it with a nul-terminating character ('\0'
or 0
, they are equivalent)
It's quite simple, e.g.:
len = strlen (s); /* get length of s */
if (len && s[len - 1] == '\n') /* check for \n */
s[--len] = 0; /* overwrite with \0 */
note: by using --len
you now have the new length preserved in len
.
Finally, for your encodechar
function, you need to know how many elements of table
you have. For each character in s
you will compare it to each table[i].source
if a match is found, then you will assign table[i].code
to t
and go to the next character. If not found, you will simply assign the character in s
to t
.
note: there is no need for the 5th element of table
(e.g. '\0'
, '\0'
), you can easily nul-terminate t
without it -- and it is not a replacement.
Putting that together, you could write encodechar
similar to the following:
void encodechar (rule *table, size_t sz, char *s, char *t)
{
size_t i;
while (*s) { /* for each character */
int replaced = 0; /* replaced flag */
for (i = 0; i < sz; i++) /* for each element of table */
if (*s == table[i].source) { /* is char == table[i].source */
*t = table[i].code; /* replace it */
replaced = 1; /* set replaced flag */
break; /* get next character */
}
if (!replaced) /* if not replaced */
*t = *s; /* copy from s to t */
s++, t++; /* increment s and t */
}
*t = 0; /* nul-terminate t */
}
Putting it altogether, and noting main()
is type int
and therefore returns a value (See: C11 Standard §5.1.2.2.1 Program startup (draft n1570). See also: See What should main() return in C and C++?), you can do something similar to the following:
#include <stdio.h>
#include <string.h>
#define MAXC 80 /* maximum characters for input buffer */
typedef struct {
char source;
char code;
} rule;
void encodechar (rule *table, size_t sz, char *s, char *t);
int main (void) {
char s[MAXC] = "", t[MAXC] = "";
rule table[] = { {'a', 'd'}, {'b', 'z'}, {'z', 'a'}, {'d', 'b'} };
size_t len = 0, n = sizeof table/sizeof *table;
printf ("Source string : ");
if (!fgets (s, MAXC, stdin)) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
len = strlen (s); /* get length of s */
if (len && s[len - 1] == '\n') /* check for \n */
s[--len] = 0; /* overwrite with \0 */
encodechar (table, n, s, t);
printf ("Encoded string: %s\n", t);
return 0;
}
void encodechar (rule *table, size_t sz, char *s, char *t)
{
size_t i;
while (*s) { /* for each character */
int replaced = 0; /* replaced flag */
for (i = 0; i < sz; i++) /* for each element of table */
if (*s == table[i].source) { /* is char == table[i].source */
*t = table[i].code; /* replace it */
replaced = 1; /* set replaced flag */
break; /* get next character */
}
if (!replaced) /* if not replaced */
*t = *s; /* copy from s to t */
s++, t++; /* increment s and t */
}
*t = 0; /* nul-terminate t */
}
Example Use/Output
$ ./bin/encode
Source string : abcdefghijklmnopqrstuvwxyz
Encoded string: dzcbefghijklmnopqrstuvwxya
Always compile with warnings enabled, and do not accept code until it compiles cleanly without warning. To enable warnings add -Wall -Wextra
to your gcc
compile string. (add -pedantic
for several additional warnings). For VS (cl.exe
on windoze), add /Wall
. For clang
, add -Weverything
. Read and understand each warning. They will identify any problems, and the exact line on which they occur. You can learn as much about coding by simply listening to what your compiler is telling you as you can from most tutorials.
Look things over and let me know if you have further questions.