My intention was to use the command line to read input and store it into an array and modify the characters of the array. If the character is '1', then turn it into '0', vice versa. I successfully store the input into an array, yet failed to modify the characters of the array. If I put 0000000000000000000000000000000(32bits) into my program, the output doesn't change.
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *a = argv[argc-1];
char arr[33];
size_t length = strlen(a);
for(size_t i=0;i<length;i++) {
arr[i]=a[i];
}
for(int j=0; j<32;j++) {
if(arr[j]=='0') {
arr[j]='1';
}
if(arr[j]=='1') {
arr[j]='0';
}
}
for(int k=0;k<32;k++) {
printf("%c",arr[k]);
}
}
If I put 0000000000000000000000000000000(32bits) into my program, the output doesn't change.
First of all, your program is not processing bits of input but it is processing the characters of input you are passing as command line argument to your program. If you want to process the bits of input, to start with, read about bitwise operators first.
Look at this for loop:
for(int j=0; j<32;j++) {
if(arr[j]=='0') {
arr[j]='1';
}
if(arr[j]=='1') {
arr[j]='0';
}
}
If current processing arr element value is '0', the second if condition in the for loop body will nullify the effect of first if condition on that arr element i.e. the arr element value will be unchanged and if the current processing arr element value is '1' than it will be set to '0'. So, after the loop, all the elements of array arr, which have original value as either '1' or '0', will set to '0' and that's the flaw in your logic.
Few suggestions:
If program is supposed to receive command line argument('s), make sure to put check on argc value. In your case, user is supposed to pass the string comprised of '0's and '1's, so you should check on argc value, something like:
if (argc != 2) {
printf ("Usage: <exe_name> <string_of_0s_and_1s>\n");
return 1;
}
Since, you do not have check on argc value in your program, if user do not pass any string from command line, the value of argc may be 1 and ,in this case, argv[argc-1] (or argv[0]) represents the program name or if the program name is not available from the host environment than argv[0][0] will be the null character. If argv[0] represents program name whose length is greater than 32 characters then your program will land up in undefined behaviour territory because there is no check on whether the command line input string length is <= 32 characters while copying it to arr buffer.
Since you are copying the input to char array (not as string) declare arr as array of 32 characters and not 33 characters. Looks like, you have assumed the input will be of size <= 32 characters. There is no problem with this assumption as long as program is running in a controlled environment where you are taking care of it. But still, by chance, if input string length is > 32 characters then your program behaviour will be undefined as it will end up processing array arr beyond it's size. You should add a check on length of input string as well:
if (length > 32) {
printf ("Input string length is >= 33 character.\n" \
"The permitted input string length is <= 32 characters.\nExiting..\n");
return 1;
}
If you want the input string to be of exact 32 characters, you can add check if (length != 32).
While copying the string, you can also add check on the characters of input string and if it contain character other than '1' and '0' then throw error message and exit.
Putting these altogether :
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[]) {
char *a = NULL;
char arr[32];
if (argc != 2) {
printf ("Usage: <exe_name> <string_of_0s_and_1s>\n");
return 1;
}
a = argv[argc-1];
size_t length = strlen(a);
if (length > 32) {
printf ("Input string length is > 32 characters.\n" \
"The permitted input string length is <= 32 characters.\nExiting..\n");
return 1;
}
for (size_t i = 0; i < length; i++) {
if ((a[i] != '1') && (a[i] != '0')) {
printf ("Found a character other than characters '1' and '0' in the input string.\n" \
"The input string should comprised of characters `1' and '0' only.\nExiting..");
return 1;
}
arr[i] = a[i];
}
for (size_t j = 0; j < length; j++) {
if (arr[j] == '0') {
arr[j] = '1';
} else {
arr[j] = '0';
}
}
for (size_t k = 0; k < length; k++) {
printf ("%c", arr[k]);
}
return 0;
}
you forget to give an else if condition in this part of the code.
for(int j=0; j<32;j++) {
if(arr[j]=='0') {
arr[j]='1';
}
else if(arr[j]=='1') { //This part should be else if
arr[j]='0';
}
}
In your code for the value of 0 it changed to 1. But for another if condition the value changed to 0 again.
To copy string you need to copy null character as well.
size_t length = strlen(a);
14 for(size_t i=0;i<=length;i++){
15 arr[i]=a[i];
But you do not need to traverse the string twice
size_t i=0;
while((arr[i]=a[i])) i++;
Your if is wrong. It should be
if(arr[j]=='0') arr[j]='1';
else arr[j]='0';
Related
I want to check a passcode if it contain at least 2 numbers.
I tried it with a double for loop like this:
for(int i = 0; i <= count; i++)
{
for(int k = 0; k < 10; k++)
{
if(passcode[i] == k)
{
printf("yee\n");
break;
}
}
}
but it doesn't work
I thought for each 'round', k would be a number from 0 to 9, and if it would be equal to a number the user gave, it would (in this case) print something
(passcode is an input from the user and count is the amount of signs given in)
int sum = 0;
for(int i = 0; i <= count; i++)
{
if (passcode[i] >= '0' && passcode[i] <= '9')
{
sum++
}
}
if (sum >=2)
printf("At least two digits");
As mentioned in some comments, you can also use isdigit(), if you have access to this function.
One other important point (also in the comments): characters and their number meaning might be different: '2' is different from 2: '2' is a character, there are 256 ASCII characters. If you want to verify this with a number, you are generally dealing with the ASCII code of that character (which is 50 for the character '2').
the digits are just ascii values you need single comparision like.
int len = LENGHT_OF_STRING;
char * s = "the string";
for(int i = 0; i < len; i++){
if(s[i] >= '0' && s[i] <= '9'){
prinf("Found digit.");
}
}
your comparision of k belongs to [0, 10) is not a valid implementaion.
This is doing comparision of ascii value of i'th char to the above range.
You have another option -- let strpbrk() do the work for you. strpbrk() (in string.h) locates the first occurrence within a string of any of the characters specified in the second accept string. So in the case of digits, your accept string is simply "0123456789". The function returns a pointer to the first occurrence found, so you simply loop twice adding 1 to the returned pointer address before the second iteration, considering any NULL return a failure to find two digits in the string.
A short working example is:
#include <stdio.h>
#include <string.h>
#define DIGITS "0123456789"
#define NDIGITS 2
int main (int argc, char **argv) {
int ndigits = NDIGITS;
char *p = argv[1];
if (argc < 2 ) { /* validate 1 argument given for password */
fprintf (stderr, "error: insufficient input,\n"
"usage: %s password\n", argv[0]);
return 1;
}
while (ndigits--) { /* loop NDIGITS times */
if (!(p = strpbrk (p, DIGITS))) { /* get ptr to digit (or NULL) */
fputs ("error: password lacks 2 digits.\n", stderr);
return 1;
}
p += 1; /* increment pointer by 1 for next search */
}
puts ("password contains at least 2 digits");
}
Example Use/Output
$ ./bin/passwd2digits some2digitpass1
password contains at least 2 digits
or
$ ./bin/passwd2digits some2digitpass
error: password lacks 2 digits.
Let strpbrk() worry about how to find the digits -- all you need to do it use it. man 3 strpbrk
Checklist:
This program takes two strings and displays, without doubles, the
characters that appear in either one of the strings.
The display will be in the order characters appear in the command
line, and will be followed by a \n.
If the number of arguments is not 2, the program displays \n.
Code:
#include <unistd.h>
int main(int argc, char *argv[])
{
int used[255] = {0};
int i = 1, j = 0;
if(argc == 3)
{
while(i < 3)
{
j = 0;
while(argv[i][j])
{
if(!used[(unsigned char)argv[i][j]])
{
used[(unsigned char)argv[i][j]] = 1;
write(1, &argv[i][j], 1);
}
j++;
}
i++;
}
}
write(1, "\n", 1);
return (0);
}
I understand argument passing part that
argv[0] is the program name,argv[1] is the second string in the string array argv, and strings are character arrays so argv[1][0] is the first character in the second string, argv[1][1] is the second character in the second string and so on.
but how does the below part works how is it printing unique characters only once from both arguments?
j = 0;
while(argv[i][j])//while argv[i][j] != '\0'
{
if(!used[(unsigned char)argv[i][j]])
{
used[(unsigned char)argv[i][j]] = 1;
write(1, &argv[i][j], 1);
}
j++;
}
I cannot get the logic. Somebody, who is a C expert, please help me to understand the logic. Thanks for your help.
if(!used[(unsigned char)argv[i][j]])
This is using the char as an index in the array. So for example everytime you get the char 'e' it will check the index 101 in the array and see if it's been used already. Basically it's directly mapping ASCII values to an array. https://theasciicode.com.ar/
It's perhaps easier to understand if you break the code up a bit:
int index = argv[i][j]; //Use the character's ASCII value as an index.
if(used[index] == 0) //If this character has NOT appeared before
{
used[index] = 1; //Mark this index as "used"
//do stuff with unique character.
}
Given a string containing alphanumeric characters, calculate the sum of all numbers present in the string.
The problem with my code is that it displays the integers present before the characters, but it is not summing up the integers after the characters.
The execution is easy in python and C++ but I cant get it done using C! Can anyone please verify where I have done wrong? << thank you !
enter code here
#include<stdio.h>
#include<string.h>
int convert(char[]);
int main()
{
char ch[100],temp[100]={0};
int i=0,s=0,j=0,n;
scanf("%s",ch);
for(i=0;i<strlen(ch);i++)
{
if((ch[i]>='0') && (ch[i]<='9'))
{
temp[j]=ch[i];
j++;
}
else
{
if(temp[0]== '\0')
{
continue;
}
else
{
n=convert(temp);
s+=n;
temp[0]= '\0';
j=0;
}
}
}
printf("%d",s);
return 0;
}
int convert(char s[]) //converting string to integer
{
int n=0;
for(int i=0;i<strlen(s);i++)
{
n= n * 10 + s[i] - '0';
}
return n;
}
Input : 12abcd4
Expected output : 16
But the output is 12 for my code.
There are two problems in your code. The first was mentioned in the comments : if the last character is a digit, the last "number section" will not be taken into account. But I don't think that the solution given in the comments is good because if the last character is not a digit, you will have a wrong value. To correct this, I added an if statement that check if the last character is a digit, if so call convert().
The second problem is that strlen return the number of characters in you string from the beginning until it finds an '\0'. The way you used your string lead to the follow problem :
ch = "12abcd4".
At first you have temp = '1' + '2' + '\0'...
After calling convert() you set temp[0] to '\0', thus temp = '\0' + '2' + '\0'... .
And when you start reading digit again, you set '4' in temp[0]. Your string is now : '4' + '2' + '\0'... .
The n returned will be 42 and your result 54 (12+42). There are several solution to have the expected behavior, I chose to use your variable j to indicate how many characters should be read instead of using strlen() :
#include<stdio.h>
#include<string.h>
int convert(char[], int size);
int main() {
char ch[100],temp[100]={0};
int i=0,s=0,j=0,n;
scanf("%s",ch);
for(i=0;i<strlen(ch);i++) {
if((ch[i]>='0') && (ch[i]<='9')) {
temp[j]=ch[i];
j++;
// change here
if(i == strlen(ch) - 1) {
n=convert(temp, j);
s+=n;
}
}
else {
// change here
n=convert(temp, j);
s+=n;
if(temp[0]== '\0') {
continue;
}
temp[0]= '\0';
j=0;
}
}
printf("%d\n",s);
return 0;
}
//change here
int convert(char s[], int size) {
int n=0;
for(int i=0;i<size;i++) {
n= n * 10 + s[i] - '0';
}
return n;
}
You could use a combination of strtoul() and strpbrk() to do this.
Declare two character pointers start_ptr and end_ptr and make start_ptr point to the beginning of the string under consideration.
char *start_ptr=s, *end_ptr;
where s is the character array of size 100 holding the string.
Since your string has only alphanumeric characters, there is no - sign and hence there are no negative numbers. So we can get away with using unsigned integers.
We are using strtoul() from stdlib.h to perform the string to integer conversion. So let's declare two variables: rv for holding the value returned by strtoul() and sum to hold the sum of numbers.
unsigned long rv, sum_val=0;
Now use a loop:
for(; start_ptr!=NULL; )
{
rv = strtoul(start_ptr, &end_ptr, 10);
if(rv==ULONG_MAX && errno==ERANGE)
{
//out of range!
printf("\nOut of range.");
break;
}
else
{
printf("\n%lu", rv);
sum_val += rv;
start_ptr=strpbrk(end_ptr, "0123456789");
}
}
strtoul() will convert as much part of the string as possible and then make end_ptr point to the first character of the part of the string that could not be converted.
It will return ULONG_MAX if the number is too big and errno would be set to ERANGE.
Otherwise the converted number is returned.
strpbrk() would search for a set of characters (in this case the characters 0-9) and return a pointer to the first match. Otherwise NULL is returned.
Don't forget to include the following header files:
stdlib.h ---> strtoul
string.h ---> strpbrk
limits.h ---> ULONG_MAX
errno.h ---> errno
In short, we could make the program to something like
for(; start_ptr!=NULL; sum_val += rv, start_ptr=strpbrk(end_ptr, "0123456789"))
{
rv = strtoul(start_ptr, &end_ptr, 10);
if(rv==ULONG_MAX && errno==ERANGE)
{
//out of range!
break;
}
}
printf("\n\n%lu", sum_val);
So the value of sum_val for the string "12abcd4" would be 16.
scanf() is usually not the best way to accept input that is not well-formatted. Maybe you can use fgets()-sscanf() combo instead.
If you must use scanf(), make sure that you check the value returned by it, which in your case must be 1 (the number of successful assignments that scanf() made).
And to prevent overflow, use a width specifier as in
scanf("%99s",ch);
instead of
scanf("%s",ch);
as 100 is the size of the ch character array and we need one extra byte to store the string delimiter (the \0 character).
I'm relatively new to coding array functions in C. After numerous tries, I've decided to surrender and ask for help.
I wish to the user to input the words and store them into the 2d array words. The problem is that it prints the words but also prints out random characters.
#include "mp1_lib.h"
void get_words(int n, char words[][16])
{
char c = ' ';
char check;
for(int x=0; x <= n; x++)
{
for(int y=0; y < 16; y++)
{
c = getchar();
check = c;
if (check == '\n')
{
break;
}
words[x][y] = c;
}
}
}
void print_words(int n, char words[][16])
{
for(int x=1; x <= n; x++)
{
for(int y=0; y < 16; y++)
{
if (words[x][y] == '\n')
{
break;
}
putchar(words[x][y]);
}
printf("\n");
}
}
In C, a string is an array of characters with the nul-terminating character '\0' as the character that marks the end of the contents of the string within the array. That is how all string functions like strlen or printf using the '%s' format specifier to print a string -- know where the string stops.
If you do not nul-terminate the array of characters -- then it is not a string, it is simply an array and you cannot pass an un-terminate array to any function expecting a string - or it won't know where the string ends (and in the case of printf will just print whatever unspecified character happens to be in memory until it comes upon a '\0' to stop the output (or SegFaults).
If you don't nul-terminate the words in your array, then you will have to have some way to store the number of characters in each word, so your print function will know where to stop printing. (if you have a two-letter word like "Hi" in a 16-char array, you can only print 2 characters from the array. Especially if it is an uninitialized array, then you will simply get gibberish printed for characters 3-16.
Your second problem is -- "How do you know how many words you have stored in your array?" -- you don't return a value from getwords, so unless you change the function type to int and return the number of words that you stored in your array, your only other option is to pass a pointer to an integer and update the value at that address so the value is available back in the calling function. Either way is fine, you generally only worry about making a value available through a pointer if you are already returning another value and need a second method to make another updated value visible back in the calling function (main() here).
Putting those pieces together, and passing a pointer to the number of words to getwords to make the number of words entered available back in main() (so you know how many words print_words has to print), you could do something similar to the following:
#include <stdio.h>
#include <ctype.h>
#define MAXC 16 /* if you need constants, define them */
#define MAXW 32
void getwords (char (*words)[MAXC], int *n)
{
int col = 0; /* column count */
while (*n < MAXW) { /* while words < MAXW */
int c = getchar(); /* read char */
/* column reaches MAXC-1 or if whitespace or EOF */
if (col == MAXC - 1 || isspace(c) || c == EOF) {
if (col) { /* if col > 0 */
words[(*n)++][col] = 0; /* nul-terminate, increment n */
col = 0; /* set col to zero */
}
if (c == EOF) /* if char EOF - all done */
return;
}
else /* otherwise - just add char to word */
words[*n][col++] = c;
}
}
void prnwords (char (*words)[MAXC], int n)
{
for (int i = 0; i < n; i++) /* loop over each of n-words & print */
printf ("words[%2d]: %s\n", i, words[i]);
}
int main (void) {
char words[MAXW][MAXC] = {""}; /* intiliaze words all zero */
int nwords = 0; /* number of words zero */
getwords (words, &nwords);
prnwords (words, nwords);
return 0;
}
(note: when reading characters into the words array, you must check the number of character read again the maximum characters per-word (MAXC) and the number of words against the maximum number of words/rows in your array (MAXW) to prevent writing outside of your array bounds -- which will invoke Undefined Behavior in your program)
(note: the ctype.h header was included to simplify checking whether the character read was whitespace (e.g. a space, tab, or newline). If you can't use it, then simply use an if (c == ' ' || c == '\t' || c == '\n') instead.)
Example Use/Output
$ echo "my dog has fleas and my cat has none" | ./bin/getwords
words[ 0]: my
words[ 1]: dog
words[ 2]: has
words[ 3]: fleas
words[ 4]: and
words[ 5]: my
words[ 6]: cat
words[ 7]: has
words[ 8]: none
Not too familiar with c. But it appears like you are not addding the new line character to the words array in get_words.
check = c;
if (check == '\n')
{
break;
}
words[x][y] = c;
So when printing in print_words this will never be true.
if (words[x][y] == '\n')
{
break;
}
That means that whatever happens to be in the memory location is what will get printed.
Your words have neither the newline character (which makes your code print garbage) nor the terminating NULLs (which makes them illegal as C strings). At least add words[x][y]="\n" before breaking the inner loop. Or, rather, move the if check after the assignment words[x][y]=c;. And yes, the loop should go from 0 to n-1.
As a side note, you do not need the variable check: just use c.
I tried to assign space as a placeholder for the 15 characters and it worked. Thanks, everyone! :)
#include "mp1_lib.h"
void get_words(int n, char words[][16])
{
char c = ' ';
char check;
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
words[x][y] = ' ';
}
}
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
c = getchar();
check = c;
if (check == '\n')
{
break;
}
words[x][y] = c;
}
}
}
void print_words(int n, char words[][16])
{
for(int x=0; x < n; x++)
{
for(int y=0; y < 16; y++)
{
putchar(words[x][y]);
}
printf("\n");
}
}
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.