#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(;i<100;i++)
{
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(;i<100;i++)
{
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
-
Please [edit] and format your question properly. It's easy, if you're able to use use a simple word processor, you can do it. – Jabberwocky Oct 28 '21 at 14:26
-
Also format your source code properly, for example like the samples if your learning material. – Jabberwocky Oct 28 '21 at 14:27
-
You are aware that you are returning arrays with local storage duration? These pointers the arrays decayed to are dangling, accessing them is undefined behaviour. The programme doing what you expect from is pure luck then... – Aconcagua Oct 28 '21 at 14:41
-
1Why are you adding 1 to encrypt but subtracting 3 to decrypt? – interjay Oct 28 '21 at 14:46
-
There's pretty much other trouble in your functions, e.g. you write to `en[i]` and `de[i]` *after* the loop where `i` got 100 alreay – which is out of bounds of the arrays in both cases, so again undefined behaviour. – Aconcagua Oct 28 '21 at 14:56
-
As you do not modify the `str` arguments it would be better to accept them as `char const*` – whereas for the return value (which is not wrong per se) it might be worth to consider (depending on how you fix your functions) if non-const `char*` possibly is the better alternative. – Aconcagua Oct 28 '21 at 14:59
-
Off-topic: It might get interesting to let caller provide the offset for Caesar – actually you'd only need one single function then as encoding by e. g. 7 could be decoded by encoding again with -7... – Aconcagua Oct 28 '21 at 15:03
-
You are calling your `encrypt` and `decrypt` functions twice each. No need for, you do not evaluate the result of first call anyway, so that one just gets discarded. – Aconcagua Oct 28 '21 at 15:13
4 Answers
You are returning a pointer to automatic variables en
and de
which are stored in the stack. This in turn means after returning from the functions encrypt
and decrypt
their place in the memory can be used by any other variable.
so to correct that, you need to define en
and de
as static.
const char *encrypt(char *str){
static char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1){
static char de[100];
int i=0;
for(;i<100;i++){
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
Though a more suitable and safer way to implement that would be:
#include<stdio.h>
void encrypt(char *str, char *encStr);
void decrypt(char *str1, char* decStr);
int main()
{
char str[100], encDecStr[100];
//Encryption
printf("Enter String for encryption\n");
scanf("%s", str);
encrypt(str, encDecStr);
printf("%s after encryption is %s\n",str,encDecStr);
//Decryption
printf("Enter String for decryption\n");
scanf("%s", str);
decrypt(str, encDecStr);
printf("%s after decryption is %s",str,encDecStr);
return 0;
}
void encrypt(char *str, char *encStr)
{
for(char *c = str; *c != '\0'; c++)
{
*encStr++ = *c + 1;
}
*encStr='\0';
}
void decrypt(char *str1, char* decStr)
{
for(char *c = str1; *c != '\0'; c++)
{
*decStr++ = *c - 1;
}
*decStr++='\0';
}
Note: The code was not fully tested for different use cases.

- 663
- 4
- 12
-
Using static variables is a problematic solution, as it can cause issues when calling the function more than once, and it doesn't support multithreading. The idiomatic method is to have the caller supply the output array (or just work in-place). – interjay Oct 28 '21 at 14:44
-
-
@interjay, That's simply not true. Calling the function more than once is just fine. Regarding Multithreading, any use of static or global variables (i.e. shared variables) can be problematic. So when ever programming for multi-threading, critical sections shall be used to avoid race conditions and so on. – Alaa Mahran Oct 28 '21 at 14:51
-
The disadvantage of this approach is that the function is not thread-safe any more. It might be worth to consider other alternatives like returning a dynamically allocated array (-> `malloc` – with risk of caller forgetting to free again -> possible memory leak), changing the input array in place (with disadvantage of having to copy input into a backup if it is yet needed afterwards) or letting the caller provide the buffer (which I consider the most flexible). – Aconcagua Oct 28 '21 at 14:53
-
-
@AlaaMahran Consider `char const* en1 = encrypt(someInputVar); char const* en2 = encrypt(anotherInputVarWithDifferentContent);` Now `en1` and `en2` both contain the same content while inputs differed. This is what interjay refers to... – Aconcagua Oct 28 '21 at 15:31
-
This is bringing the champion level to the beginner playground which is not always a great idea. By the way, the above code will work if the user used en1 before calling the function again. Anyway, I edited the answer to give the OP a future insight. – Alaa Mahran Oct 28 '21 at 17:08
There are quite a number of errors in your code:
- Returning arrays with local storage duration:
The array's life time ends (i.e. it ceases to exist) as soon as you exit from the function, thus the pointer returned is dangling, reading from it is undefined behaviour - You write beyond the bounds of your local array:
en[i] = '\0'
withi
being 100 after the loop is out of the range of valid indices from 0 to 99, which again is undefined behaviour. - You have differing offsets for encrypting (1) and decrypting (3).
- Simply adding an offset without further checks (or modulo operations) will produce different character sets for input and output strings (might be your least problem...).
- You always en-/decode the entire array, which is more than actually needed. Additionally the terminating null character then is encoded as well, resulting in different lengths of input and output and garbage at the end of encoded string.
- Use of
gets
is dangerous as it allows a user to write beyond the input array, resulting in undefined behaviour. This is the reason why it actually has been removed from C language with C11 standard – which introduces a safe alternativegets_s
. Yet another alternative (especially for pre-C11 code) is fgets.
For the dangling pointer problem there are several options:
- Making the array static (as mentioned already):
The disadvantage of this approach is that the function is not thread-safe any more. Additionally calling the function more than once overwrites previous results, if you haven't evaluated already or copied them they are lost. - Returning a dynamically allocated array, see malloc function.
This comes with the risk of the caller forgetting to free the allocated memory again, which would result in a memory leak - Changing the input array in place:
Disadvantage of is having to copy the input into a backup if it is yet needed afterwards. - Letting the caller provide the buffer.
Last option is most flexible and most idiomatic one, so I'll concentrate on this one:
void caesar(char const* input, char* output, int offset)
{
int const NumChars = 'z' - 'a';
offset = offset % NumChars + NumChars;
// ^ assures valid range, can still be negative
// ^ assures positive value, possibly
// out of range, but will be fixed later
for(;*input; ++input, ++output)
{
int c = *input - 'a';
// distance from character a
c = (c + offset) % NumChars;
// ^ fixes too large offset
*output = 'a' + c;
}
// as now iterating *until* null character found we now *need*
// to add it (in contrast to original version with whole array!)
*output = 0;
}
This variant includes an interesting idea: Let the caller define the offset to be applied! The modulo operation assures the valid range of the character, no matter how large the offset is. The great thing about: If a user encoded with some number n
, exactly the same function can be used to decode again with -n
(which is why I simply named it caesar
according to the algorithm it implements). Note that this is untested code; if you find a bug please fix yourself...
Be aware, though, that this code still has two weaknesses:
- It assumes ASCII encoding or compatible – at least one where letters a to z are in contiguous range, a is first character, z is last one. This is not true for all encodings, though, consider the (in-?)famous EBCDIC.
- It assumes all input is in range of Latin minuscules only (from a - z), it does not consider white-space, digits, capital letters, punctuation marks... You might want to include special handling for all of these or at least the ones you might use.
You could fix these e.g. (many other variants are thinkable as well) by
- converting all characters to either upper or lower case (
toupper((unsigned char)*input)
– assuming case doesn't matter) - search in an array of valid characters (
"ABC...XYZ012...89"
) for the appropriate index and if found encode like above withNumChars
being array length, otherwise (whitespace, punctuation) just leave as is.
In any case, the function would then be called like:
char input[128]; // prefer powers of 2 for array lengths...
char en[sizeof(input)];
char de[sizeof(input)];
gets_s(input, sizeof(input));
caesar(input, en, 7);
// en contains encrypted string, could e.g. be printed now
caesar(en, de, -7);
// de contains decrypted string
// you could even encode/decode in place:
caesar(input, input, 7);
// just be aware that this will fail, though, for the case if input
// and output overlap and input starts before output, as then at
// some point already encoded values will be read as input again:
// caesar(input, input + 1, 7) fails!!!

- 24,880
- 4
- 34
- 59
Your code does not handle a special case for the character 'z'. Thus
en[i]=str[i]+1;
Causes the character '{' to be written to the array en
instead. For learning more about why this happens, I recommend you look at ASCII tables and looking at the integer values for alphabets.
Secondly, did you mean to type -3 in there?
de[i]=str1[i]-3;
This won't work if you're planning on using the decrypt()
function to decrypt strings that you made using encrypt()
because you're adding 1 to the character while encrypting and then subtracting a different number when decrypting, so the result will appear garbled.
I rewrote your code for you, since this is a beginner program, I made as little changes as possible so you can understand it. I WOULD HIGHLY RECOMMEND NOT USING gets()
though... See here.
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
encrypt(str);
printf("%s after encryption is %s\n", str, encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
decrypt(str1);
printf("%s after decryption is %s", str1, decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'z')
{
en[i] = 'a';
continue;
}
en[i] = str[i] + 1;
}
en[i] = '\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'a')
{
en[i] = 'z';
continue;
}
de[i] = str1[i] - 1;
}
de[i] = '\0';
return de;
}
Some criticisms
- Like I said,
gets()
is really bad... See here for more details. Although it might be too complicated for you... A better alternative isfgets
!
fgets(str, num, stdin)
takes user input from the console, and then stores it inside the array str
, which must be large enough to store at least num
characters. Don't worry about stdin
if you don't know what that means. But be sure to always write it when using fgets
as an alternative to gets
- Like others have already posted, albeit using more technical jargon, it's a bad idea to declare an array inside a function and then return that array. You know the function ends when the
return
statement is hit, and at that point all the variables that were declared inside the function will get destroyed.
That doesn't necessarily mean that you can't read the data that was in them, but it becomes a probabilistic game where there's a teeny-tiny chance that the array will get corrupted after the function exits and before the data in that array is read. This is technically Undefined Behaviour.
I hope you know about pointers. You can modify the array which you passed as a parameter directly and then return that array, thus avoiding accessing an array outside it's lifetime.

- 1
- 1
-
-
Definitely, although you should be able to tell that OP is a beginner and hence I don't wanna overcomplicate things for them. Notice how I'm still using `gets()` – Ahnaf Abdullah Oct 28 '21 at 15:02
-
It will generate an issue from time to time. Basically every time the program run, it might give a different result. – Alaa Mahran Oct 28 '21 at 17:09
There's some issues in your code :
Not a very big issue for a beginner , but you should avoid
gets
function. Because it doesn't check the input , it can cause buffers overflow and various security problems , try usingfgets
instead.In encrypt , and decrypt functions , you are returning the address of an array located in the stack of the function , look :
const char *encrypt(char *str){ char en[100]; int i=0; for(;i<100;i++){ en[i]=str[i]+1; } en[i]='\0'; return en; }
Here , Since the en
array is declared inside the function , after the return you may get garbage string when trying to read it.
The solution here , is to either malloc
it , or declare a static array outside the function , and initialize it.
- You are encrypting by adding 1 to the value of the string , and decrypt it by retrieving 3 . I don't know if this is what you intended to do.
Here's a new version of your code , try to check if it suits your need :
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
static char de[100] , en[100] ;
const char *decrypt(char *str1){
memset(de , 0 , 100) ;
int i=0;
for(;i<strlen(str1);i++){
de[i]=str1[i]-1;
}
de[i]='\0';
return (const char*) de;
}
const char* encrypt(char* str){
memset(en , 0 , 100) ;
int i=0;
for(;i<strlen(str);i++){
en[i]=str[i]+1;
}
en[i]='\0';
return (const char*) en;
}
int main(){
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}

- 362
- 3
- 15
-
1There's no need to `memset`ting the array to 0 as you are going to overwrite anyway, and you retained the undefined behaviour for writing beyond array bounds. The global variable comes with the same problems the static variable local to the function (thread-safety), but introduces many more for the array being accessible from anywhere. Global variables really should be avoided whenever possible – and here there are quite a number of better alternatives! – Aconcagua Oct 28 '21 at 15:24
-
1Additionally you are calling `strlen` with *every* loop run. Be aware that this is rather costly, so you produce an quadratic (`O(n²)`) solution for a linear (`O(n)`) problem. You could instead simply check for `str[i]` not being the null character. – Aconcagua Oct 28 '21 at 15:42
-
@Aconcagua thanks for the feedback , It is true that what I wrote can be enhanced greatly... I'll edit my answer when I have the time :) – Amine Bensalem Oct 28 '21 at 17:47