Why does this c program crashe? - c

I want to make a list of , for example 10 sentences that are entered through the keyboard. For getting a line I am using a function getline(). Can anybody explain why does this program crash upon entering the second line? Where is the mistake ?
#define LISTMAX 100
#define LINEMAX 100
#include <stdio.h>
#include <string.h>
void getline(char *);
int main ()
{
char w[LINEMAX], *list[LISTMAX];
int i;
for(i = 0; i < 10; i++)
{
getline(w);
strcpy(list[i], w);
}
for(i = 0; i < 10; i++)
printf("%s\n", list[i]);
return 0;
}
void getline(char *word)
{
while((*word++ = getchar()) != '\n');
*word = '\0';
}

A string is a block of memory (an array), which contains chars, terminated by '\0'. A char * is not a string; it's just a pointer to the first char in a string.
strcpy does not create a new string. It just copies the data from one block of memory to another. So your problem is: you haven't allocated a block of memory to hold the string.
I'll show you two solutions. The first solution is: change the declaration of list so that the memory is already allocated. If you do it this way, you can avoid using strcpy, so your code is simpler:
// no need for w
char list[10][LISTMAX];
// ...
// get the line straight into list
// no need to copy strings
getline(list[i]);
But if you want to stretch yourself, the second solution is to allocate the block of memory when you know you'll need it. You need to do this a lot in C, so maybe now is a good time to learn this technique:
#include <stdlib.h> // include the malloc function
// ...
char w[LINEMAX], * list[LISTMAX]
// put this line between the getline and strcpy lines
list[i] = (char *) malloc((strlen(w) + 1) * sizeof(char));
This solution is more complicated, but you only allocate as much memory as you need for the string. If the string is 10 characters long, you only request enough memory to hold 11 characters (10 characters + '\0') from the system. This is important if, say, you want to read in a file, and you've no idea how big the file will be.
By the way, why do you have LINEMAX and LISTMAX as separate constants? Can you think of a reason why they might be different? And why haven't you made 10 a constant? Wouldn't this be better?
#define LINEMAX 100
#define NUMBER_OF_LINES 10
// ...
char list[NUMBER_OF_LINES][LINEMAX];
// ...
for (i = 0; i < NUMBER_OF_LINES; i++)

Related

How to dynamically allocate string using void function?

First of all Thanks for visiting my question... :)
I am interested in competitive programming, so I daily do some amount of problem-solving, however, I only know C language at a decent level, and I often face problems while dynamically allocating something as usual, especially for strings and 2D arrays.
But I somehow manage to find ways (thanks to StackOverflow), for example, I wanted to create a function that scans string dynamically until the user enters space or new line, so I came up with the solution below and it works perfectly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
ptr = (char *)malloc(0 * sizeof(char));
unsigned int size = 0;
char c = 0;
while (1)
{
scanf("%c", &c);
if (c == 32 || c == 10)
{
break;
}
size++;
ptr = (char *)realloc(ptr, size * sizeof(char));
ptr[size - 1] = c;
}
ptr = (char *)realloc(ptr, (size + 1) * sizeof(char));
ptr[size] = '\0';
return ptr;
}
int main()
{
char *str;
str = create_string(str);
printf("%s", str);
printf("\n%lu", strlen(str));
return 0;
}
And now for curiosity purposes, I want to know how can I do this same thing using the void function?, something like:
char *str;
create_string(&str);
should start storing everything in the dynamic memory which is pointed by str.
Also, please if you have more knowledge to show in DMA for 2D array, then please show me it, feel free to give examples with different problems.
And also How can I stop scanning the string (which was allocated dynamically) with specific string ending? for example, scanning(any kind of scanning, i.e. int, bool, custom structures etc...) should stop if user enters string "STOP", Please feel free to give pictorial examples.
Because I am sure that this question is burning like a fire in beginner's and intermediate C programmers' minds.
As C passes arguments by value, to return something via an out parameter, you need to pass in a pointer to it. So to return a char * it would:
void create_string(char **s) {
*s = malloc(42);
}
Here is your refactored code. I changed the following:
Eliminate return value of update caller.
Initialize *ptr = malloc(1) for the trailing '\0'. It eliminates an unnecessary and implementation defined malloc(0). This also eliminates the (*ptr)[size] = ... which looks wrong as the last index is expected to be size - 1. Alternatively initialize it to NULL.
Use character constants instead of magic values (32, 10).
sizeof(char) is defined as 1 so leave it out.
Reduced scope of variable c.
free() memory allocated.
(cosmetic) Use size_t size instead of unsigned int size.
(cosmetic) Avoid the noise of casting casting void *.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void create_string(char **ptr) {
*ptr = malloc(1);
size_t size = 1;
for(;;) {
char c;
scanf("%c", &c);
if (c == ' ' || c == '\n') break;
(*ptr)[size-1] = c;
size++;
*ptr = realloc(*ptr, size);
}
(*ptr)[size-1] = '\0';
}
int main() {
char *str;
create_string(&str);
printf("%s\n", str);
printf("%zu\n", strlen(str));
free(str);
}
I didn't fix these issue:
Check return value of malloc(), realloc().
v = realloc(v, ...) is unsafe and will leak memory if realloc() fails. You need to do char *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;.
Check return value of scanf() otherwise you may be operating on uninitialized data.
Use scanf("%s", ..) instead of for(;;) { scanf("%c", ...). It's more efficient to allocate a chunk at a time instead of per byte.
If user enters ctrl-d (EOF) the program will go into an infinite loop.
It's good idea to separate i/o from logic (i.e. let caller do the scanf(). That way create_string() is much more reusable.

strcpy not working inside for loop? c programming

I am writing a program that loops through a text file with two columns. the first values are strings and the second are ints. I am trying to put them in arrays based on their column.
Data example:
stephen 170
shane 150
jake 180
Im trying to do this:
["stephen", "shane", "jake"]
[170,150,180]
For some reason the strcpy function is not working. I am not getting an error message but when I use strcpy and attempt to print the first value of the string array, nothing happens.
#include <stdio.h>
#include <string.h>
int main (void) {
FILE* dict;
char word[50];
int weight;
int weights[50000];
char *words[50000];
dict = fopen("dict.txt", "r");
for (int i = 0; i < 50000; i++) {
fscanf(dict, "%s %d", &word, &weight);
weights[i] = weight;
strcpy(word, words[i]);
}
printf("%s", words[0]);
printf("%d", weights[0]);
return 0;
}
First note that the parameters of strcpy are in the wrong order: the first is the destination and the second is the source, and I guess you want to copy the word string to word[i], so you need to swap the parameters order.
But this won't work either as word[i] points to garbage memory. You'll have to allocate some. You could use for example strdup instead:
words[i] = strdup(word);
Note that it allocates memory on the heap so don't forget to free it once you finished using it.
You have swapped destination and source in your call to strcpy.
Checking man or using a good IDE showing lib function prototypes should help you to avoid that kind of stupid errors for good.
Also, it's mere luck that the program isn't segfaulting as you are reading from words[i] which is an uninitialized array of pointers to chars, you should add a malloc of words[i] before copying to it.
A minimaly fixed (there are still other problems to fix) version of the program could look like below
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
FILE* dict;
char word[50];
int weight;
int weights[50000];
char *words[50000];
dict = fopen("dict.txt", "r");
for (int i = 0; i < 50000; i++) {
fscanf(dict,"%s %d", &word, &weight);
weights[i] = weight;
words[i] = malloc(strlen(word)+1);
strcpy(words[i], word);
}
printf("%s", words[0]);
printf("%d", weights[0]);
return 0;
}
Another option would be to use strdup rather than the current code because it does both malloc and strcpy.
Other obvious problems are that your program will have troubles if any word is longer than 50 characters and it's not trivial to fix using scanf. You could use something like fscanf(dict,"%49s %d", &word, &weight); to avoid overflowing word but if the word is too long that will break the parsing loop. (you will get a line with the beginning of the word and the previous value of weight).
And another issue will happen if your dictionary file has less than 50000 entries.
Let's say that the content of your dictionary file has expected format rather than fixing the code.

Convert int to string, then fill the array with the converted elements

Iam trying to fill array with numbers that i converted from int to string. The output iam trying to get is {"0", "1", "2"...} but my array is filled with the last number that i converted {"19", "19", "19"..} idk why is that. Could you please help me guys ?
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *arr[20] = {};
for(int i = 0;i < 20;i++){
char str[20];
itoa(i, str, 10);
arr[i] = str;
}
for(int i = 0;i < 20;i++){
printf("%s\n", arr[i]);
}
}
Problem
char str[20]; arranges that str is a pointer to the first element of a chunk of memory containing 20 chars. Since the str is a local variable to the for loop, you cannot be sure what happens to that memory after the current iteration finishes. It is undefined behaviour.
With that in mind, think about what arr will be at the the end of the first for loop.
It will be an array of 20 pointers to some bit of memory. But you can no longer be sure what the memory contains. It may be, as in your case, that they all point to the same bit of memory, which is filled with the last string that itoa put there. This might not happen in general though.
Solution
To fix this, you should probably use malloc to allocate new memory for each string you want to keep, within the first for loop. The memory is then heap allocated, and you can be sure that each call to malloc will give you a chunk of unused memory, such that you won't be overwriting previous strings. Try for example:
for(int i = 0;i < 20;i++){
char *str = (char *) malloc(sizeof(char) * 20);
itoa(i, str, 10);
arr[i] = str;
}
Note that it is also good practice to explicitly free memory you have allocated with malloc.
char str[20]; creates a single location in memory where str is stored. It does not create a new location each time the loop is run.
arr[i] = str; points each element of arr at that one location, which by the end of the loop contains just "19".
Instead of arr[i] = str; you need to do something like strcpy(arr[i], str) to copy the current contents of str to the appropriate element of arr.
Also, as Scott Hunter pointed out, you should declare arr using char arr[20][20] to have 20 unique char arrays to actually write the strings into.
I tested the following code (changed itoa to sprintf) and it worked for me:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char arr[20][20] = {};
for(int i = 0;i < 20;i++){
char str[20];
sprintf(str, "%i", i);
strcpy(arr[i], str);
}
for(int i = 0;i < 20;i++){
printf("%s\n", arr[i]);
}
}
Unrolling the loop, you get
arr[0] = str;
....
arr[1] = str;
....
arr[2] = str;
.... // etc
Which is basically:
arr[0] = arr[1] = arr[2] = arr[3] (...) = str;
So yeah, they all point to the same string. There is only one str.
There's also some undefined behaviour here. Firstly, all of your pointers arr[0] etc are being dereferenced here:
printf("%s\n", arr[i]);
when the thing they point to, str, has gone out of scope, there is no guarantee what might happen when you access it. Infact, the first "instance" of str goes out of scope at the end of the first iteration of the first loop. When you assign arr[1]=str, arr[0] is techincially invalid already. However, it likely that there is just one str that remains on the stack for the duration of the function, which would be consistent with the observed behaviour, but not guaranteed.
Try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char arr[20][20] = {}; // Allocate the space to store the results
for(int i = 0;i < 20;i++){
char str[20]; // Temp store
itoa(i, str, 10);
strcpy (arr[i], str); // Copy the string from the temp store
// str goes out of scope NOW at the end of the loop, you cannot
// any pointer that points to it either outside this loop or the next time
// around the loop
}
// etc
you need to allocate memory for each place in the array, arr. you can do this on the stack or on the heap. In this approach i have allocated the strings on the heap. So i called malloc() for allocating buffers of size int (no need to allocate more).
In my approach i have used sprintf() from stdio.h to convert the numbers to string format.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INT_DIGITS_NUM 20
int main() {
char* arr[20]; /*this is an array of 20 char pointers*/
for(int i = 0;i < 20;i++){
arr[i] = (char*)malloc(sizeof(char) * MAX_INT_DIGITS_NUM);
sprintf(arr[i], "%d", i);
}
for(int i = 0;i < 20;i++){
printf("%s\n", arr[i]);
/*now you need to free all previous allocated buffers*/
free(arr[i]);
}
return 0;
}
what is wrong with your code?
arr is only an array to char pointers! its not really holding string buffers that you can use for copy or scan to it! its only pointers that points to some address.
inside the for loop, you are declaring str buffer and you keep override it (itoa keeps copying to it) to the same place!! hence you exit the for loop in last iteration with only the last converted i!
now, just to aware you, after existing the for loop all the local variables marked by the os as released! so this can lead to memory corruption or override later in the program!
keep in mind that in my solution i always allocates MAX_INT_DIGITS_NUM bytes, no matter the i deget length. this is waste of memory! keep in mind that itoa() is not standard in C or ansi c!

Copying strings from extern char environ in C

I have a question pertaining to the extern char **environ. I'm trying to make a C program that counts the size of the environ list, copies it to an array of strings (array of array of chars), and then sorts it alphabetically with a bubble sort. It will print in name=value or value=name order depending on the format value.
I tried using strncpy to get the strings from environ to my new array, but the string values come out empty. I suspect I'm trying to use environ in a way I can't, so I'm looking for help. I've tried to look online for help, but this particular program is very limited. I cannot use system(), yet the only help I've found online tells me to make a program to make this system call. (This does not help).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern char **environ;
int main(int argc, char *argv[])
{
char **env = environ;
int i = 0;
int j = 0;
printf("Hello world!\n");
int listSZ = 0;
char temp[1024];
while(env[listSZ])
{
listSZ++;
}
printf("DEBUG: LIST SIZE = %d\n", listSZ);
char **list = malloc(listSZ * sizeof(char**));
char **sorted = malloc(listSZ * sizeof(char**));
for(i = 0; i < listSZ; i++)
{
list[i] = malloc(sizeof(env[i]) * sizeof(char)); // set the 2D Array strings to size 80, for good measure
sorted[i] = malloc(sizeof(env[i]) * sizeof(char));
}
while(env[i])
{
strncpy(list[i], env[i], sizeof(env[i]));
i++;
} // copy is empty???
for(i = 0; i < listSZ - 1; i++)
{
for(j = 0; j < sizeof(list[i]); j++)
{
if(list[i][j] > list[i+1][j])
{
strcpy(temp, list[i]);
strcpy(list[i], list[i+1]);
strcpy(list[i+1], temp);
j = sizeof(list[i]); // end loop, we resolved this specific entry
}
// else continue
}
}
This is my code, help is greatly appreciated. Why is this such a hard to find topic? Is it the lack of necessity?
EDIT: Pasted wrong code, this was a separate .c file on the same topic, but I started fresh on another file.
In a unix environment, the environment is a third parameter to main.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[], char **envp)
{
while (*envp) {
printf("%s\n", *envp);
*envp++;
}
}
There are multiple problems with your code, including:
Allocating the 'wrong' size for list and sorted (you multiply by sizeof(char **), but should be multiplying by sizeof(char *) because you're allocating an array of char *. This bug won't actually hurt you this time. Using sizeof(*list) avoids the problem.
Allocating the wrong size for the elements in list and sorted. You need to use strlen(env[i]) + 1 for the size, remembering to allow for the null that terminates the string.
You don't check the memory allocations.
Your string copying loop is using strncpy() and shouldn't (actually, you should seldom use strncpy()), not least because it is only copying 4 or 8 bytes of each environment variable (depending on whether you're on a 32-bit or 64-bit system), and it is not ensuring that they're null terminated strings (just one of the many reasons for not using strncpy().
Your outer loop of your 'sorting' code is OK; your inner loop is 100% bogus because you should be using the length of one or the other string, not the size of the pointer, and your comparisons are on single characters, but you're then using strcpy() where you simply need to move pointers around.
You allocate but don't use sorted.
You don't print the sorted environment to demonstrate that it is sorted.
Your code is missing the final }.
Here is some simple code that uses the standard C library qsort() function to do the sorting, and simulates POSIX strdup()
under the name dup_str() — you could use strdup() if you have POSIX available to you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char **environ;
/* Can also be spelled strdup() and provided by the system */
static char *dup_str(const char *str)
{
size_t len = strlen(str) + 1;
char *dup = malloc(len);
if (dup != NULL)
memmove(dup, str, len);
return dup;
}
static int cmp_str(const void *v1, const void *v2)
{
const char *s1 = *(const char **)v1;
const char *s2 = *(const char **)v2;
return strcmp(s1, s2);
}
int main(void)
{
char **env = environ;
int listSZ;
for (listSZ = 0; env[listSZ] != NULL; listSZ++)
;
printf("DEBUG: Number of environment variables = %d\n", listSZ);
char **list = malloc(listSZ * sizeof(*list));
if (list == NULL)
{
fprintf(stderr, "Memory allocation failed!\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < listSZ; i++)
{
if ((list[i] = dup_str(env[i])) == NULL)
{
fprintf(stderr, "Memory allocation failed!\n");
exit(EXIT_FAILURE);
}
}
qsort(list, listSZ, sizeof(list[0]), cmp_str);
for (int i = 0; i < listSZ; i++)
printf("%2d: %s\n", i, list[i]);
return 0;
}
Other people pointed out that you can get at the environment via a third argument to main(), using the prototype int main(int argc, char **argv, char **envp). Note that Microsoft explicitly supports this. They're correct, but you can also get at the environment via environ, even in functions other than main(). The variable environ is unique amongst the global variables defined by POSIX in not being declared in any header file, so you must write the declaration yourself.
Note that the memory allocation is error checked and the error reported on standard error, not standard output.
Clearly, if you like writing and debugging sort algorithms, you can avoid using qsort(). Note that string comparisons need to be done using strcmp(), but you can't use strcmp() directly with qsort() when you're sorting an array of pointers because the argument types are wrong.
Part of the output for me was:
DEBUG: Number of environment variables = 51
0: Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.tQHOVHUgys/Render
1: BASH_ENV=/Users/jleffler/.bashrc
2: CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/soq/src
3: CLICOLOR=1
4: DBDATE=Y4MD-
…
47: VISUAL=vim
48: XPC_FLAGS=0x0
49: XPC_SERVICE_NAME=0
50: _=./pe17
If you want to sort the values instead of the names, you have to do some harder work. You'd need to define what output you wish to see. There are multiple ways of handling that sort.
To get the environment variables, you need to declare main like this:
int main(int argc, char **argv, char **env);
The third parameter is the NULL-terminated list of environment variables. See:
#include <stdio.h>
int main(int argc, char **argv, char **environ)
{
for(size_t i = 0; env[i]; ++i)
puts(environ[i]);
return 0;
}
The output of this is:
LD_LIBRARY_PATH=/home/shaoran/opt/node-v6.9.4-linux-x64/lib:
LS_COLORS=rs=0:di=01;34:ln=01;36:m
...
Note also that sizeof(environ[i]) in your code does not get you the length of
the string, it gets you the size of a pointer, so
strncpy(list[i], environ[i], sizeof(environ[i]));
is wrong. Also the whole point of strncpy is to limit based on the destination,
not on the source, otherwise if the source is larger than the destination, you
will still overflow the buffer. The correct call would be
strncpy(list[i], environ[i], 80);
list[i][79] = 0;
Bare in mind that strncpy might not write the '\0'-terminating byte if the
destination is not large enough, so you have to make sure to terminate the
string. Also note that 79 characters might be too short for storing env variables. For example, my LS_COLORS variable
is huge, at least 1500 characters long. You might want to do your list[i] = malloc calls based based on strlen(environ[i])+1.
Another thing: your swapping
strcpy(temp, list[i]);
strcpy(list[i], list[i+1]);
strcpy(list[i+1], temp);
j = sizeof(list[i]);
works only if all list[i] point to memory of the same size. Since the list[i] are pointers, the cheaper way of swapping would be by
swapping the pointers instead:
char *tmp = list[i];
list[i] = list[i+1];
list[i+1] = tmp;
This is more efficient, is a O(1) operation and you don't have to worry if the
memory spaces are not of the same size.
What I don't get is, what do you intend with j = sizeof(list[i])? Not only
that sizeof(list[i]) returns you the size of a pointer (which will be constant
for all list[i]), why are you messing with the running variable j inside the
block? If you want to leave the loop, the do break. And you are looking for
strlen(list[i]): this will give you the length of the string.

Segmentation Fault in Simple Offset Encryption

Alright guys, this is my first post here. The most recent assignment in my compsci class has us coding a couple of functions to encode and decode strings based on a simple offset. So far in my encryption function I am trying to convert uppercase alphas in a string to their ASCII equivalent(an int), add the offset(and adjust if the ASCII value goes past 'Z'), cast that int back to a char(the new encrypted char) and put it into a new string. What I have here compiles fine, but it gives a Segmentation Fault (core dumped) error when I run it and input simple uppercase strings. Where am I going wrong here? (NOTE: there are some commented out bits from an attempt at solving the situation that created some odd errors in main)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//#include <stdlib.h>
char *encrypt(char *str, int offset){
int counter;
char medianstr[strlen(str)];
char *returnstr;// = malloc(sizeof(char) * strlen(str));
for(counter = 0; counter < strlen(str); counter++){
if(isalpha(str[counter]) && isupper(str[counter])){//If the character at current index is an alpha and uppercase
int charASCII = (int)str[counter];//Get ASCII value of character
int newASCII;
if(charASCII+offset <= 90 ){//If the offset won't put it outside of the uppercase range
newASCII = charASCII + offset;//Just add the offset for the new value
medianstr[counter] = (char)newASCII;
}else{
newASCII = 64 + ((charASCII + offset) - 90);//If the offset will put it outside the uppercase range, add the remaining starting at 64(right before A)
medianstr[counter] = (char)newASCII;
}
}
}
strcpy(returnstr, medianstr);
return returnstr;
}
/*
char *decrypt(char *str, int offset){
}
*/
int main(){
char *inputstr;
printf("Please enter the string to be encrypted:");
scanf("%s", inputstr);
char *encryptedstr;
encryptedstr = encrypt(inputstr, 5);
printf("%s", encryptedstr);
//free(encryptedstr);
return 0;
}
You use a bunch of pointers, but never allocate any memory to them. That will lead to segment faults.
Actually the strange thing is it seems you know you need to do this as you have the code in place, but you commented it out:
char *returnstr;// = malloc(sizeof(char) * strlen(str));
When you use a pointer you need to "point" it to allocated memory, it can either point to dynamic memory that you request via malloc() or static memory (such as an array that you declared); when you're done with dynamic memory you need to free() it, but again you seem to know this as you commented out a call to free.
Just a malloc() to inputstr and one for returnstr will be enough to get this working.
Without going any further the segmentation fault comes from your use of scanf().
Segmentation fault occurs at scanf() because it tries to write to *inputstr(a block of location inputstr is pointing at); it isn't allocated at this point.
To invoke scanf() you need to feed in a pointer in whose memory address it points to is allocated first.
Naturally, to fix the segmentation fault you want to well, allocate the memory to your char *inputstr.
To dynamically allocate memory of 128 bytes(i.e., the pointer will point to heap):
char *inputstr = (char *) malloc(128);
Or to statically allocate memory of 128 bytes(i.e., the pointer will point to stack):
char inputstr[128];
There is a lot of complexity in the encrypt() function that isn't really necessary. Note that computing the length of the string on each iteration of the loop is a costly process in general. I noted in a comment:
What's with the 90 and 64? Why not use 'A' and 'Z'? And you've commented out the memory allocation for returnstr, so you're copying via an uninitialized pointer and then returning that? Not a recipe for happiness!
The other answers have also pointed out (accurately) that you've not initialized your pointer in main(), so you don't get a chance to dump core in encrypt() because you've already dumped core in main().
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
char *encrypt(char *str, int offset)
{
int len = strlen(str) + 1;
char *returnstr = malloc(len);
if (returnstr == 0)
return 0;
for (int i = 0; i < len; i++)
{
char c = str[i];
if (isupper((unsigned char)c))
{
c += offset;
if (c > 'Z')
c = 'A' + (c - 'Z') - 1;
}
returnstr[i] = c;
}
return returnstr;
}
Long variable names are not always helpful; they make the code harder to read. Note that any character for which isupper() is true also satisfies isalpha(). The cast on the argument to isupper() prevents problems when the char type is signed and you have data where the unsigned char value is in the range 0x80..0xFF (the high bit is set). With the cast, the code will work correctly; without, you can get into trouble.

Resources