I want to use pipes to read a string in child process and send it to the parent, then count the number of characters in the string and display the number. The program runs only until I input a string. Can you please tell me what I'm doing wrong?
#include <stdlib.h>
#include <stdio.h>
#include<string.h>
#define SIZE 1024
int main()
{
int i,n,x;
char msg[SIZE];
char str[SIZE];
int p3[2];
pipe(p3);
int pid=fork();
if(pid==0){
close(p3[0]); //closing read end
printf("Enter a string\n");
fgets(msg,SIZE,stdin);
write(p3[1],msg,sizeof(msg)); //writting into pipe
close(p3[1]); //closing write end
}
else {
close(p3[1]); //close write end
read(p3[0], str, sizeof(str));
int c = 0;
while (str[c] != "Done")
{
for(i=0; i<sizeof(str);i++){
if (str[c] >= 'a' && str[c] <= 'z') {
c++;
}
}
}
printf("%d letters\n", c);
}
return 0;
}
Use strlen to determine the length of the string then use for loop to iterate upto the length, something like below:
if (strncmp(str, "Done", 4) == 0)
exit(0);
int len = strlen(str);
for (l = 0; l < len; l++)
{
if (str[l] >= 'a' && str[l] <= 'z')
{
c++;
}
}
printf("%d letters\n", c);
close(p3[0]); //close write end
You can use strlen() to determine the length of any null-terminated string;
In while (str[c] != "Done") you're comparing a char to a string literal. You should use strcmp() or strncmp() to compare strings;
The inner-loop (for(i=0; i<sizeof(str);i++) {...}) is using str[c], but I believe you want str[i], besides, the loop is not counting (c++) when the char is not in the interval [a,z], therefore your outer-loop may never end;
You really don't need nested loops. Try something like:
const char *ptr = str;
size_t index = 0; // An index to access str - just to help you.
// Iterate over ptr, one character at a time, until we find the null terminator.
while (*ptr != '\0') {
// Read 4 chars from ptr and check if it's "Done"
if (strncmp(ptr, "Done", 4) == 0)
break;
// Do something here. For example:
// if (str[index] >= 'a' && str[index] <= 'z')
// lowercase_counter++;
// if (str[index] >= 'A' && str[index] <= 'Z')
// uppercase_counter++;
// if (str[index] >= '0' && str[index] <= '9')
// number_counter++;
// NOTE: str[index] is equivalent to *ptr, thus you can use one or another.
ptr++;
index++;
}
Be sure to not increment ptr elsewhere - the idea is for each loop iteration to check a single character - you can still read ahead using strcmp or whatever, like we did for "Done". If you do that, also take care to not access ptr beyond the str boundaries.
Related
I need to build a function that gets an input and capitalizes only the first letter, doesn't print numbers, capitalizes after a . for a new sentence, and capitalizes all words between a double quotation marks ".
This is what I got until now:
#include <stdio.h>
#define MAX 100
int main()
{
char str[MAX] = { 0 };
int i;
//input string
printf("Enter a string: ");
scanf("%[^\n]s", str); //read string with spaces
//capitalize first character of words
for (i = 0; str[i] != '\0'; i++)
{
//check first character is lowercase alphabet
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
if (str[i] == '.')//check dot
{
//if dot is found, check next character
++i;
//check next character is lowercase alphabet
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
}
else
{
//all other uppercase characters should be in lowercase
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32; //subtract 32 to make it small/lowercase
}
}
printf("Capitalize string is: %s\n", str);
return 0;
}
I cant find a way to remove all numbers from input and convert all lowercase to uppercase inside a " plus code for not printing numbers if user input them.
if I input
I am young. You are young. All of us are young.
"I think we need some help. Please" HELP. NO, NO NO,
I DO NOT
NEED HELP
WHATSOEVER.
"Today’s date is
15/2/2021"...
I am 18 years old, are you 20 years old? Maybe 30 years?
output:
I am young. You are young. All of us are young.
"I THINK WE NEED SOME HELP. PLEASE" help. No, no no,
i do not
need help
whatsoever.
"TODAY’S DATE IS
//"...
I am years old, are you years old? maybe years?
The C standard library provides a set of functions, in ctype.h, that will help you
Of particular interest, would be:
isdigit() - returns true if digit
isalpha() - returns true if alphabet character
isalnum() - returns true if alpha/numeric character
islower() - returns true if lower case character
isupper() - returns true if upper case character
tolower() - converts character to lower case
toupper() - converts character to upper case
So, for example, you could replace the test/modify with:
if ( islower( str[i] ) )
{
str[i] = toupper( str[i] );
}
Pedantically, islower() and toupper() return an unsigned int but that's a separate matter...
You can remove letters from a string if you keep two indices, one for reading and one for writing. The following loop will remove all digits from a string:
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (!isdigit(c)) str[j++] = c;
}
str[j] = '\0';
(I've used to character classification functions from <ctype.h> mentioned in Andrew' answer.)
This is safe, because j will always be smaller or equal to i. Don't forget to mark the end of the filtered string with the nullterminator, '\0'. You can combine this filtering with your already existing code for replacing characters.
In your code, you capitalize letters only if they are directly behind a full stop. That's usually not the case, there's a space between full stop and the next word. It's better to establish a context:
shift: capitalize the next letter (beginning or after full stop.)
lock: capitalize all letters (inside quotation marks.)
When you read a letter, decide whether to capitalize it or not depending of these two states.
Putting the filtering and the "shift context§ together:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "one. two. THREE. 4, 5, 6. \"seven\", eight!";
int shift = 1; // Capitalize next letter
int lock = 0; // Capitalize all letters
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (isdigit(c)) continue;
if (isalpha(c)) {
if (shift || lock) {
str[j++] = toupper(c);
shift = 0;
} else {
str[j++] = tolower(c);
}
} else {
if (c == '"') lock = !lock;
if (c == '.') shift = 1;
str[j++] = c;
}
}
str[j] = '\0';
puts(str);
printf("(length: %d)\n", j);
return 0;
}
In order to remove some characters, you should use 2 index variables: one for reading and one for writing back to the same array.
If you are allowed to use <ctype.h>, it is a much more portable and efficient way to test character types.
Also do not use scanf() with protection against buffer overflow. It is as bad as using gets(). Given the difficulty in specifying the maximum number of bytes to store into str, you should use fgets() instead of scanf().
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#define MAX 100
int main() {
char str[MAX];
int i, j;
unsigned char last, inquote;
//input string
printf("Enter a string: ");
if (!fgets(str, sizeof str, stdin)) { //read string with spaces
// empty file
return 1;
}
last = '.'; // force conversion of first character
inquote = 0;
//capitalize first character of words
for (i = j = 0; str[i] != '\0'; i++) {
unsigned char c = str[i];
//discard digits
if (isdigit(c)) {
continue;
}
//handle double quotes:
if (c == '"') {
inquote ^= 1;
}
//upper case letters after . and inside double quotes
if (last == '.' || inquote) {
str[j++] = toupper(c);
} else {
str[j++] = tolower(c);
}
if (!isspace(c) && c != '"') {
// ignore spaces and quotes for the dot rule
last = c;
}
}
str[j] = '\0'; // set the null terminator in case characters were removed
printf("Capitalized string is: %s", str);
return 0;
}
This function is meant to fill a second string with the filtered results of the first. the filter should remove all special characters and only print lower case permutations of all letters written
I've tried changing the nature of the "ModifyText" loop, and I've done it with pointers+while loop and with for loops both with the condition of ending when the iterator reaches a character \0.
These are the methods I've already tried, both continue to only return the lowercase "the" of the first word in the string, not the entire string with only lowercase alphabet letters
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//
//int ModifyText(char Stringboy[], char output[])
//{
// for(int i=0; Stringboy[i] != '\0'; i++)
// {
// if(Stringboy[i] >= 'A' && Stringboy[i] <= 'Z')
// {
// output[i] = Stringboy[i] + 32;
//
// }
// else if(Stringboy[i] >= 'a' && Stringboy[i] <= 'z')
// {
// output[i] = Stringboy[i];
// }
//}}
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
}
int main(void){
char samplearray[] = {"THE quick Brown Fox jumps over the Lazy Dog!***!"};
char dummy[83];
printf("Original Text: \n %s\n", samplearray);
ModifyText(samplearray, dummy);
printf("Modified Text: \n %s\n", dummy);
//letterCounter(dummy); //these two bottom functions have their prints written into them, so they need only be called
//wordCounter(dummy);
printf("length of sample array is %d", strlen(samplearray));
}
This code is only returning a string "the" when it should be returning a string "the quick brown fox jumps over the lazy dog" in the string entitled dummy
When *Stringboy is a space then you do not set *output since neither if condition is true. However, you do increment output. As a result the character after "the" in output will be random data (in your case is is probably NULL) which is why the string ends.
Change the code to this:
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
*output = '\0';
That way the spaces will be written to the output string.
In your original code, you increment the output pointer also when you didn't copy a letter. You either should write something (e.g. a space) or not increment the output pointer. If you increment the output pointer without writing something, whatever character was there before will stay there. If you're lucky that character is a zero (terminating your string), but it can also be any weird character, including character 7 (a bell sound).
Also, don't forget that your output string needs a terminating zero. Otherwise, weird uninitialized characters might pop up at the end of your string.
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
++output;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
++output;
}
++Stringboy;
}
*output = '\0'; // make sure the output gets a terminating zero
}
Here is a more fancy version, that outputs spaces to replace non-letters. To not get the output flooded with spaces, a boolean variable checks to maximally output one space between the words.
int ModifyText(char *Stringboy, char *output)
{
bool previousWasLetter = false;
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
++output;
previousWasLetter = true;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
++output;
previousWasLetter = true;
}
else if (previousWasLetter)
{
*output = ' ';
++output;
previousWasLetter = false;
}
++Stringboy;
}
*output = '\0'; // make sure the output gets a terminating zero
}
You have several mistakes:
You copy characters to a new string only if character is an uppercase letter or if the character is lowercase... but you don't copy anything, when it's not either. As you feed the function with an array allocated in the stack (recently allocated, so probably you got a new page zero filled) the character there could be a \0 char and so, delimited the string. You need to copy the character untouched in case it's not an uppercase character... not only if it is lowercase. This will allow you to copy the spaces (which are neither) for example. Resulting in this code:
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else // if(*Stringboy >= 'a' && *Stringboy <= 'z') // not needed
{
*output = *Stringboy;
}
you dont finalize the output string, putting a \0 character at the end. You should do it past the end of the loop, as the output pointer has been left pointing to the next output char, just add
*output = '\0';
next to the loop.
Some other minor changes (these cannot be considered mistakes, but will silence some warnings got from the compiler on some permitted language inconsistencies you made), like adding a return 0; statement to nonvoid returning functions (this should be a mistake in case you planned to return something from it), change the %d length format for a more portable %zd format string (if you have strlen() returning a long value and int and long are different size, this could lead to problems in some machines), and adding a new line \n character, so the shell prompt gets printed in the next line (and not just after the string length).
So, the code finally should be something like:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//
//int ModifyText(char Stringboy[], char output[])
//{
// for(int i=0; Stringboy[i] != '\0'; i++)
// {
// if(Stringboy[i] >= 'A' && Stringboy[i] <= 'Z')
// {
// output[i] = Stringboy[i] + 32;
//
// }
// else if(Stringboy[i] >= 'a' && Stringboy[i] <= 'z')
// {
// output[i] = Stringboy[i];
// }
//}}
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else // if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
*output = '\0';
return 0;
}
int main(void){
char samplearray[] = "THE quick Brown Fox jumps over the Lazy Dog!***!"; // braces unneeded.
char dummy[83];
printf("Original Text: \n %s\n", samplearray);
ModifyText(samplearray, dummy);
printf("Modified Text: \n %s\n", dummy);
//letterCounter(dummy); //these two bottom functions have their prints written into them, so they need only be called
//wordCounter(dummy);
printf("length of sample array is %zd\n", strlen(samplearray));
return 0;
}
Reposting because my first post was no good. I have a question that I'm not really sure how to do. I know the process I'm going for, but am not totally sure how to scan a string into an array so that each character/integer is scanned into a independent element of the array. I'll post the question and the code I have so far, and any help would be appreciated.
Question:
Assume that we have a pattern like the following: ([n][letter])+ in which n is an integer number and letter is one of the lowercase letters from a-z. For example, 2a and 3b are valid expressions based on our pattern. Also, “+” at the end of the pattern means that we have at least one expression (string) or more than one expression attached. For instance, 2a4b is another valid expression which is matched with the pattern. In this question, we want to convert these valid expressions to a string in which letters are repeated n times.
o Read an expression (string) from user and print the converted version of the expression in the output.
o Check if input expression is valid. For example, 2ab is not a valid expression. If the expression is not valid, print “Invalid” in the output and ask user to enteranother expression.
o Sample input1 = “2a”, output = aa
o Sample input2 = “2a3b”, output = aabbb
o You will receive extra credit if you briefly explain what concept or theory you can use to check whether an expression is valid or not.
What I have so far:
#include <stdio.h>
int main()
{
int size, i, j;
char pattern[20];
char vowel[20];
int count[20];
printf("Please enter your string: ");
gets(pattern);
size = strlen(pattern);
for(i=0; i<size; i++)
if((i+1)%2 == 0)
vowel[i] = pattern[i];
else if((i+1)%2 != 0)
count[i] = pattern[i];
for(i=0; i<size/2; i++);
for(j=0; j<count[i]; j++)
printf("%s", vowel[i]);
}
I assumed you want to write the "invalid\n" string on stderr. If not just change the file descriptor given to write.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INPUT_SIZE 20
int
check_input(char *input)
{
while (*input)
{
if (*input < '0' || *input > '9')
{
write(2, "invalid\n", 8);
return 1;
}
while (*input >= '0' && *input <= '9')
input++;
if (*input < 'a' || *input > 'z')
{
write(2, "invalid\n", 8);
return 1;
}
input++;
}
return 0;
}
void
print_output(char *input)
{
int i;
while (*input)
{
i = atoi(input);
while (*input >= '0' && *input <= '9')
input++;
for (; i > 0; i--)
write(1, input, 1);
input++;
}
write(1, "\n", 1);
}
int
main()
{
char input[MAX_INPUT_SIZE];
do
{
printf("Please enter your string: ");
fgets(input, MAX_INPUT_SIZE, stdin);
input[strlen(input) - 1] = '\0';
}
while (check_input(input));
print_output(input);
return 0;
}
The steps are:
Read pattern
Check if pattern is valid
Generate output
Since the input length is not specified you have to assume a maximum length.
Another assumption is n is a single digit number.
Now you may read the whole expression with fgets() or read it char by char.
The latter allows you to check for validity as you read.
Lets use fgets() for convenience and in case the expression needs to be stored for later use.
char exp[100]; // assuming at most 50 instances of ([n][letter])
int len;
printf("Input: ");
fgets(exp, 100, stdin);
len = strlen(exp) - 1; // Discard newline at end
An empty input is invalid. Also a valid expression length should be even.
if (len == 0 || len%2 != 0) {
printf("Invalid-len\n");
return 1;
}
Now parse the expression and separately store numbers and letters in two arrays.
char nums[50], letters[50];
invalid = 0;
for (i = 0, j = 0; i < len; i += 2, j++) {
if (exp[i] >= '1' && exp[i] <= '9') {
nums[j] = exp[i] - '0';
} else {
invalid = 1;
break;
}
if (exp[i+1] >= 'a' && exp[i+1] <= 'z') {
letters[j] = exp[i+1];
} else {
invalid = 1;
break;
}
}
Notice that in each iteration if first char is not a number or second char is not a letter, then the expression is considered to be invalid.
If the expression is found to be invalid, nothing to do.
if (invalid) {
printf("Invalid\n");
return 1;
}
For a valid expression run nested loops to print the output.
The outer loop iterates for each ([n][letter]) pattern.
The inner loop prints n times the letter.
printf("Output: ");
for (i = 0; i < len/2; i++) {
for (j = 0; j < nums[i]; j++)
printf("%c", letters[i]);
}
This is a rather naive way to solve problems of this type. It is better to use regular expressions.
C standard library doesn't have regex support. However on Unix-like systems you can use POSIX regular expressions.
like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define prompt "Please enter your string: "
void occurs_error(const char *src, const char *curr){
printf("\nInvalid\n");
printf("%s\n", src);
while(src++ != curr){
putchar(' ');
}
printf("^\n");
}
bool invalid(char *pattern){
char *p = pattern;
while(*p){
if(!isdigit((unsigned char)*p)){//no number
occurs_error(pattern, p);
break;
}
strtoul(p, &p, 10);
if(!*p || !islower((unsigned char)*p)){//no character or not lowercase
occurs_error(pattern, p);
break;
}
++p;
}
return *p;
}
int main(void){
char pattern[20];
while(fputs(prompt, stdout), fflush(stdout), fgets(pattern, sizeof pattern, stdin)){
pattern[strcspn(pattern, "\n")] = 0;//chomp newline
char *p = pattern;
if(invalid(p)){
continue;
}
while(*p){
int n = strtoul(p, &p, 10);
while(n--)
putchar(*p);
++p;
}
puts("");
}
}
I'm new to C and programming. I got stuck at a homework exercise. My output only shows the first character in upper case, and the following characters in some weird numbers. Can someone take a look at my code and give me some tips on what I've done wrong and ways to fix the issue? Your help is greatly appreciated!
"Write a function void sticky(char* word) where word is a single word such as “sticky” or “RANDOM”. sticky() should modify the word to appear with “sticky caps” (http://en.wikipedia.org/wiki/StudlyCaps), that is, the letters must be in alternating cases(upper and lower), starting with upper case for the first letter. For example, “sticky” becomes “StIcKy” and “RANDOM” becomes “RaNdOm”. Watch out for the end of the string, which is denoted by ‘\0’. You can assume that legal strings are given to the sticky() function."
#include <stdio.h>
#include <stdlib.h>
/*converts ch to upper case, assuming it is in lower case currently*/
char toUpperCase(char ch)
{
return ch-'a'+'A';
}
/*converts ch to lower case, assuming it is in upper case currently*/
char toLowerCase(char ch)
{
return ch-'A'+'a';
}
void sticky(char* word){
/*Convert to sticky caps*/
for (int i = 0; i < sizeof(word); i++)
{
if (i % 2 == 0)
{
word[i] = toUpperCase(word[i]);
}
else
{
word[i] = toLowerCase(word[i]);
}
}
}
int main(){
/*Read word from the keyboard using scanf*/
char word[256];
char *input;
input = word;
printf("Please enter a word:\n");
scanf("%s", input);
/*Call sticky*/
sticky(input);
/*Print the new word*/
printf("%s", input);
for (int i = 0; i < sizeof(input); i++)
{
if (input[i] == '\n')
{
input[i] = '\0';
break;
}
}
return 0;
}
you need to use strlen not sizeof to find the length of a char* string
Modify your change upper and change lower function
/*converts ch to upper case,*/
char toUpperCase(char ch)
{
if(ch>='a' && ch<='z')/*If condition just to make sure current letter is in lower case*/
return ch-'a'+'A';
}
/*converts ch to lower case, assuming it is in upper case currently*/
char toLowerCase(char ch)
{
if(ch>='A' && ch<='Z')/*If condition just to make sure current letter is in Upper case*/
return ch-'A'+'a';
}
Also, only four characters are converted since you are using sizeof for finding the string length.sizeof always returns 4(depends upon machine).
use strlen(word) to find the length of string word in following for loop:
for (int i = 0; i < strlen(word); i++)
{
}
You should use strlen instead of sizeof.
Also, you must check whether your letter is already upper or lower case:
for (int i = 0; i < strlen(word); i++)
{
if (i % 2 == 0)
{
if ( isLowerCase(word[i]) )
{
word[i] = toUpperCase(word[i]);
}
else
{
// do nothing.
}
}
else
{
if ( isUpperCase(word[i]) )
{
word[i] = toLowerCase(word[i]);
}
else
{
// do nothing.
}
}
}
Note that I haven't implemented the isUpperCase and isLowerCase functions ;D
Function sizeof() is used to calculate the size of the datatype, not the size allocated to the pointer.
So you can not use it like sizeof(word). Instead, iterate over a characters until you stumble upon a \0, which indicates end of string.
On example:
int i = 0;
while ( word[i] != 0 ) {
// do lower/upper case conversion.
}
sizeof (word) is the size of a char *, you must pass another parameter with the array size... or use strlen ().
Something is wrong in your code : you are making odd characters upper case and even ones lower but you do no check whether they were lower or upper case in the first place. But lowering an already lower-case letter gives you a wrong value (the same is true for "uppering" an already upper-case letter).
So you should do :
char toUpperCase(char ch)
{
if ((ch >= 'a') && (ch <= 'z')) {
return ch-'a'+'A';
} else {
return ch;
}
}
and the same for toLowerCase.
Thank you so much for the tips! Using your suggestions, I modified my code and it's working now.
Below is my revised code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*converts ch to upper case, assuming it is in lower case currently*/
char toUpperCase(char ch){
return ch-'a'+'A';
}
/*converts ch to lower case, assuming it is in upper case currently*/
char toLowerCase(char ch){
return ch-'A'+'a';
}
void sticky(char* word)
{
/*Convert to sticky caps*/
for (int i = 0; i < strlen(word); i++)
{
if (i % 2 == 0)
{
if (word[i] >= 'a' && word[i] <= 'z')
{
word[i] = toUpperCase(word[i]);
}
}
else
{
if (word[i] >= 'A' && word[i] <= 'Z')
{
word[i] = toLowerCase(word[i]);
}
}
}
}
int main(){
/*Read word from the keyboard using scanf*/
char word[256];
char *input;
input = word;
printf("Please enter a word:\n");
scanf("%s", input);
/*Call sticky*/
sticky(input);
/*Print the new word*/
printf("%s", input);
for (int i = 0; i < sizeof(input); i++)
{
if (input[i] == '\n')
{
input[i] = '\0';
break;
}
}
return 0;
}
Using only stdio.h, string.h and stdlib.h libraries how would I go about implementing this?
I'm quite new to programming so please bear with me!
Allocate a new char array of the same length as your string. Convince yourself that this is enough space. Don't forget the NUL.
Loop through the string, copying to the new string only those characters that are alphanumeric. You can't do this portably without also including <ctype.h> and using a function/macro from that header, unless you're going to enumerate all characters that you consider alphanumeric.
Again, don't forget the NUL.
Since this is homework, here is the verbal description:
Run a loop over the original string and use the functions isalnum() to determine if a character is alphanumeric. Maintain a second char array of reasonable size and every time you encounter an AlphaNum, insert it to that array. Once all AlphaNum characters have been copied to the second array, NULL terminate it and you have your string.
Note: isalnum() is defined in ctype.h, so if you aren't allowed to use that, you may have to define this function for yourself. That is another exercise of it's own.
Every char you read in your string is a byte (you can think it as a number between 0 and 255, and that's how the computers handle them) so you just need to check the ascii table to see what letter refers to.
Every alphanumerical char is in this range: [48, 58] (for numbers), or [65, 90] (upper case), or [97, 122] (lower case).
Look at this:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 64
int isalphanum(char); /*states if a char is alphanumerical or not*/
char *getalphanum(char *, char*); /*modifies the second string to get the result*/
int main(void) {
char in[SIZE] = "Hello, W##########orl...,.,d!"; /*just a random to try out*/
char out[SIZE];
getalphanum(in, out);
printf("%s", out);
return 0;
}
int isalphanum(char a) {
if ((a >= 48) && (a <= 58))
return 1;
if ((a >= 65) && (a <= 90))
return 1;
if ((a >= 97) && (a <= 122))
return 1;
return 0;
}
char *getalphanum(char *s, char *t) {
if ((s == NULL) || (t == NULL)) /*tests if the strings are "handble"*/
return NULL;
int i = 0;
int j = 0;
char c;
while ((c = *(s + i)) != '\0') {
if (isalphanum(c)){
*(t + j) = c;
j++;
}
i++;
}
*(t + j) = '\0';
return t;
}
This code works and is very simple and can be improved, but there is evertything you need.
The best way is to use the isalnum() from ctype.h but now that is not an option, I have written a not-standard/non-portable function called isalnum_not_prefered() which is the equivalent of ctype.h's isalnum().
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int isalnum_not_prefered(char s)
{
if((s >= 'A' && s <= 'Z') ||
(s >= 'a' && s <= 'z') ||
(s >= '0' && s <= '9'))
return 1;
return 0;
}
int main(void)
{
char str[] = "this!234$#&##$^is5##$a##$4677~=_?}valid2234kjstring";
int len = strlen(str);
int i, j=0;
char *newstr1 = NULL;
char *newstr2 = NULL;
if ((newstr1 = (char *) malloc(sizeof(char) * len + 1)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
for (i=0 ; i<len ; i++) {
if (isalnum(str[i])) {
newstr1[j] = str[i];
j++;
}
}
newstr1[j] = '\0';
if ((newstr2 = (char *) malloc(sizeof(char) * len + 1)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
j=0;
for (i=0 ; i<len ; i++) {
if (isalnum_not_prefered(str[i])) {
newstr2[j] = str[i];
j++;
}
}
newstr2[j] = '\0';
printf("string : %s \n", str);
printf("result1 : %s \n", newstr1);
printf("result2 : %s \n", newstr2);
free(newstr1);
free(newstr2);
return 0;
}
Points to note:
strings in C is terminated with \0. So the new string that your are populating should also terminate with \0
malloc()'ed memory must be free()'ed
malloc() errors should be handled
this code is not portable as it assumes the machines character set to be ASCII. If the hardware supports some other character set (say EBCDIC) then this may not work as expected.
Hope this helps!