I created a program that asks the user for a word and then it arranges the letters in that word in alphabetical order and stores it in another string.
#include <stdio.h>
main()
{
char in[100],out[100],ch;
int i,len,j=0;
//ask user for a word
printf("Enter a word: ");
scanf("%s",in);
//arrange that word in alphabetical order
for(ch = 'a'; ch <= 'z'; ++ch)
for(i = 0; i < strlen(in); ++i)
if(in[i] == ch)
{
out[j] = ch;
++j;
}
//print the word
printf("%s",out);
fflush(stdin);
getchar();
}
The problem is when word is stored in the other string, there are some extra letters or symbols after that word. Can someone please tell me what could be possibly wrong with my code?
You're not null terminating the output string. printf("%s",out); will keep outputting characters until it finds 0 ('\0'). There are many options to fix this:
terminate the output to the current iterator position after the for-loop:
out[j] = '\0';
make the output the same length as the input:
out[strlen(in)] = '\0';
declare a 0-initialized array:
char out[100] = { 0 };
fill the output array with zero's yourself:
memset(out, 0; sizeof(out));
...
As the sorting is concerned, if it's just for learning then it's fine, otherwise you should pick a more efficient sorting algorithm
C strings are null terminated
Use
out[j] ='\0';
before printf
The %s specifier searches for a null termination.
In your case it keeps on printing until it finds one, so you get some random symbols.
Also avoid use of fflush.
You might want to update your logic to sort uppercase characters too.
You might want to use a sort say bubble sort
l=strlen(in);
for(i = 0; i < l; i++)
{
for(j = i + 1; j < l - 1; j++)
if(in[j-1] > in[j]){
ch = in[j];
in[j] = in[j-1];
in[j-1] = ch;
}
}
printf("Sorted String :%s",in);
Related
I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.
The objective of my assignment is to take in user input string and then print out the English alphabetic characters (both lower case and upper case) that the user has entered.
For example if the user inputs:D_!an!_ i12el the output would be Daniel.
My approach was to loop through the input and just remove all the non alpha characters but I dont know how to.Please help with any ideas! This is what I have so far:
#include <stdio.h>
#include <string.h>
int main()
{
char my_array[100];
printf("Enter a message: ");;
while(strlen(gets (my_array)) == 0);
printf(" Your message is: %s\n", my_array);
for(int i = 0; i< strlen(my_array);i++)
{
if(my_array[i] < 'A' || my_array[i] > 'z')
{
my_array[i] = ' ';
}
}
printf(" Your new message is: %s\n", my_array);
}
EDIT:I got my loop working to print out only the alpha characters but it keeps adding extra characters when i print the elements. For example D_!a_*&Ni#32el becomes DaNielASCIIV. I dont know why this is happening.
for(int i = 0; i< 100;i++)
{
if (isalpha(message[i]))
{
putchar(message[i]);
}
}
Rather than trying to update the string you have, just print out a character if it's a letter.
Also, upper case and lower case characters don't immediately follow one another, so you need to check for them separately:
printf(" Your new message is: ");
for(int i = 0; i< strlen(my_array);i++)
{
if((my_array[i] >= 'A' && my_array[i] <= 'Z') ||
(my_array[i] >= 'z' && my_array[i] <= 'z'))
{
putchar(my_array[i]);
}
}
printf("\n");
Alternetely, you could replace the above if condition with a function that checks for this:
if (isalpha(my_array[i]))
EDIT:
The reason you're now seeing extra characters is because you changed the loop to loop over the entire array instead of the length of the string. Go back to using strlen(my_array) instead of 100 and you'll be fine.
Use this pattern for removing elements from an array
int i, j;
j = 0;
for (i=0;i<N;i++)
if (good(array[i]) )
array[j++] = array[i];
N = j;
We go through, adding everything that matches. It's efficient and in-place.
It might be better to loop through the input string and use strchr() to see if the characters are in the string "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". This has the advantages of not relying on a specific ordering for of the letters of the alphabet (see here and here), and being flexible so that you can easily change the characters that you want to pick out. You could then collect the results in a string, or print the filtered characters out directly.
char my_array[100];
char filtered_array[100];
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
char *pchar;
int j = 0;
...
for (int i = 0; i < strlen(my_array); i++)
if ((pchar = strchr(alphabet, my_array[i])) != NULL) {
filtered_array[j] = *pchar;
++j;
}
filtered_array[j] = '\0';
...
The above code collects the results in a string. Note that a null-terminator is added to the end of filtered_array[], since this character would not be copied to the new array. If you want to include spaces or hyphens in the filtered string, just add these characters to the alphabet[] string.
this is my first post in this forum so please be patient.
I need to make a short programm, where the user can enter 2 strings which should be attached afterwards.
I already got this code below (I am not allowed to use other "includes").
What I need to know is: How can I deny any spaces which the user will enter?
Example: 1. String "Hello " | 2. String "World" Result should be "HelloWorld" instead of "Hello World".
#include <stdio.h>
void main()
{
char eingabe1[100];
char eingabe2[100];
int i = 0;
int j = 0;
printf("Gib zwei Wörter ein, die aneinander angehängt werden sollen\n");
printf("1. Zeichenkette: ");
gets(eingabe1);
printf("\n");
printf("2. Zeichenkette: ");
gets(eingabe2);
printf("\n");
while (eingabe1[i] != '\0')
{
i++;
}
while (eingabe2[j] != '\0')
{
eingabe1[i++] = eingabe2[j++];
}
eingabe1[i] = '\0';
printf("Nach Verketten: ");
puts(eingabe1);
}
You have to filter out the spaces as you copy your strings.
You have two string indices, i for the first string and and j for the second string. You could make better use of these indices if you used i for the reading position (of both strings subsequently; you can "reuse" loop counters in independent loops) and j for the writing position.
Here's how. Note that the code attempts to prevent buffer overflow by only adding characters if there is space in the string. This check needs only to be done when copying the second string, because j <= i when you process the first string.
#include <stdio.h>
int main()
{
char str1[100] = "The quick brown fox jumps over ";
char str2[100] = "my big sphinx of quartz";
int i = 0;
int j = 0;
while (str1[i] != '\0') {
if (str1[i] != ' ') str1[j++] = str1[i];
i++;
}
i = 0;
while (str2[i] != '\0') {
if (str2[i] != ' ' && j + 1 < sizeof(str1)) str1[j++] = str2[i];
i++;
}
str1[j] = '\0';
printf("'%s'\n", str1);
return 0;
}
In addition to avoiding spaces between your two words, you also have to avoid the newline ('\n') character placed in the input buffer by the user pressing Enter. You can do that with a simple test after you have read the line with fgets() NOT gets(). gets() is no longer part of the standard C library and should not be used due to insecurity reasons. Plus fgets provides simple length control over the number of characters a user may enter at any time.
Below, you run into trouble when you read eingabe1. After the read, eingabe1 contains a '\n' character at its end. (as it would using any of the line-oriented input functions (e.g. getline(), fgets(), etc) To handle the newline, you can simply compare its length minus '1' after you loop over the string to find the nul character. e.g.:
if (eingabe1[i-1] == '\n') i--; /* remove trailing '\n', update i */
By simply reducing the index 'i', this will guarantee that the concatenation with eingabe2 will not have any spaces or newline characters between the words.
Putting the pieces together, and using fgets in place of the insecure gets, after #define MAX 100'ing a constant to prevent hardcoding your array indexes, you could come up with something similar to:
#include <stdio.h>
#define MAX 100
int main (void)
{
char eingabe1[MAX] = {0};
char eingabe2[MAX] = {0};
int i = 0;
int j = 0;
printf("Gib zwei Wörter ein, die aneinander angehängt werden sollen\n");
printf("1. Zeichenkette: ");
/* do NOT use gets - it is no longer part of the C library */
fgets(eingabe1, MAX, stdin);
putchar ('\n');
printf("2. Zeichenkette: ");
/* do NOT use gets - it is no longer part of the C library */
fgets(eingabe2, MAX, stdin);
putchar ('\n');
while (eingabe1[i]) i++; /* set i (index) to terminating nul */
if (i > 0) {
if (eingabe1[i-1] == '\n') i--; /* remove trailing '\n' */
while (i && eingabe1[i-1] == ' ') /* remove trailing ' ' */
i--;
}
while (eingabe2[j]) { /* concatenate string - no spaces */
eingabe1[i++] = eingabe2[j++];
}
eingabe1[i] = 0; /* nul-terminate eingabe1 */
printf("Nach Verketten: %s\n", eingabe1);
return 0;
}
Output
$ ./bin/strcatsimple
Gib zwei Wörter ein, die aneinander angehängt werden sollen
1. Zeichenkette: Lars
2. Zeichenkette: Kenitsche
Nach Verketten: LarsKenitsche
Let me know if you have any further questions. I have highlighted the changes with comments above.
/**
return: the new len of the string;
*/
int removeChar(char* string, char c) {
int i, j;
int len = strlen(string)+1; // +1 to include '\0'
for(i = 0, j = 0 ; i < len ; i++){
if( string[i] == c )
continue; // avoid incrementing j and copying c
string[ j ] = string[ i ]; // shift characters
j++;
}
return j-1; // do not count '\0';
}
int main(){
char str1[] = "sky is flat ";
char str2[100] = "earth is small ";
strcat( str2, str1 );
printf("with spaces:\n\t'%s'\n", str2) ;
removeChar(str2, ' ');
printf("without spaces:\n\t'%s'\n", str2 );
}
/**
BONUS: this will remove many characters at once, eg "\n \r\t"
return: the new len of the string;
*/
int removeChars(char* string, char *chars) {
int i, j;
int len = strlen(string);
for(i = 0, j = 0 ; i < len ; i++){
if( strchr(chars,string[i]) )
continue; // avoid incrementing j and copying c
string[ j ] = string[ i ]; // shift characters
j++;
}
string[ j ]=0;
return j;
}
Thank you everyone for all the answers.
I got the solution now.
I read some advices from you and will try to remember for the future.
See the code below:
(Excuse me for the strange names for the variables, I use german words)
A few notices:
I am not allowed to use library functions
I am not allowed to use fgets for some reasons as a trainee
#include <stdio.h>
void main()
{
char eingabe1[100];
char eingabe2[100];
int i = 0;
int j = 0;
printf("gib zwei wörter ein, die aneinander angehängt werden sollen\n");
printf("1. zeichenkette: ");
gets(eingabe1);
printf("\n");
printf("2. zeichenkette: ");
gets(eingabe2);
printf("\n");
//Attach Strings
while (eingabe1[i] != '\0')
{
i++;
}
while (eingabe2[j] != '\0')
{
eingabe1[i++] = eingabe2[j++];
}
//Remove Space
eingabe1[i] = '\0';
i = 0;
j = 0;
while (eingabe1[i] != '\0')
{
if (eingabe1[i] != 32)
{
eingabe2[j++] = eingabe1[i];
}
i++;
}
eingabe2[j] = '\0';
printf("Nach verketten: ");
puts(eingabe2);
}
Sounds like homework to me.
I just wanted to mention that you probably shouldn't use sizeof() on strings these days because there may be multibyte characters in there. Use strlen() instead. The only time sizeof() would be appropriate is if you're going to malloc() a certain number of bytes to store it.
I write little loops fairly often to do low level text stuff one character at a time, just be aware that strings in C usually have a 0 byte at the end. You have to expect to encounter one and be sure you put one on the output. Space is 0x20 or decimal 32 or ' ', it's just another character.
#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';
the user enters a secret word and then from the alphabet choses a letter and if the letter is in the secret word it turns into an asterisk. i think the problem is in the two for loops because it does no seem to replace the letter with an asterisk.
int main ()
{
char secretword[20] = {};
char alphabet[27] = {"abcdefghijklmnopqrstuvwxyz"};
char guess;
int i = 0, k = 0;
int length = 0;
length = strlen(secretword);
printf("You Get six chances to guess all of the letters in a phrase\n");
printf("Enter the secret word/phrase: ");
scanf("%s", &secretword);
printf("Past guesses: ");
printf("%s\n", alphabet);
printf("Guess a character: ");
scanf("%s", &guess);
for(i = 0; i < 27; i++)
{
for(k = 0; k < length; k++)
{
if(secretword[k] == alphabet[i])
{
secretword[k] = '*';
}
}
}
printf("%s", secretword);
return 0;
}
First off, there is a big logic error. The two for loops:
for(i = 0; i < 27; i++)
{
for(k = 0; k < length; k++)
{
if(secretword[k] == alphabet[i])
{
secretword[k] = '*';
}
}
}
Says:
for all characters in the alphabet,
iterate over all characters in the string, and then
if that character in the string is equal to the current alphabet character:
replace it with an asterisk.
Because you're iterating over the whole alphabet, you'll replace all of the string with '*'s. What you probably want is something like:
for(k = 0; k < length; k++)
{
if(secretword[k] == guess)
{
secretword[k] = '*';
}
}
instead.
There are some other problems. This needs to be after secretword is read in:
length = strlen(secretword);
Otherwise you'll read the length of the uninitalised word. Change it to something like this:
printf("You Get six chances to guess all of the letters in a phrase\n");
printf("Enter the secret word/phrase: ");
scanf("%s", &secretword);
length = strlen(secretword);
Also, this:
scanf("%s", &guess);
Should probably be:
scanf("%c", &guess);
since you're planning to only read a char rather than a string.
Also, the 27 in this line:
char alphabet[27] = {"abcdefghijklmnopqrstuvwxyz"};
Is correct, because you want to include the null terminator at the end of the string.
However, this:
for(i = 0; i < 27; i++)
Will read up to alphabet[26], which will be a '\0'. You probably don't want to replace these '\0's in the string (and you won't see any if you're only going up to strlen(secretword) characters - since strlen() counts up to the first '\0'). Changing the loop to only go to 26 characters stops you doing an unnecessary pass over the secretword. It should probably be
for(i = 0; i < strlen(alphabet); i++)
Or, even better (as suggested by wildplasser):
char alphabet[] = {"abcdefghijklmnopqrstuvwxyz"};
....
for(i = 0; i < sizeof alphabet -1; i++)
One last thing - your program will crash if you don't have enough space in the secretword array to hold the string read in. You can get around this by asking scanf to read only 19 characters:
scanf("%19s", &secretword);
Note that scanf will terminate the string with a '\0', so %19s may put up to 20 bytes in to the string.
You set the length variable before secretword is initialized with an actual string so the length will always be zero (or garbage depending on how the compiler decides to initaliaze the variable secretword).
Try putting length = strlen(secretword); after scanf("%s", &secretword);. Without entering anything, strlen() will return 0, finishing the for-loop immediately.