How to read an array and analyse the input - c

I was just wondering is there some way to read an array and then based upon the letters entered do something?
Like for example: if the roman numeral; MM was entered is there some way to see that 2 M's were entered and display the value for M?
output would be: 1000+1000.
Could you just tell me the name of the function, because it is for an assignment I dont want someone doing it for me, I just dont know where to start from.
example: char romanNumerals[2] = {"MMMCMXCVIII"};

char romanNumerals[2] = {"MMMCMXCVIII"};
Is not right as it can only hold 1 element(+1 for the \0). Change it to
char romanNumerals[] = "MMMCMXCVIII";
The compiler will choose the correct size for the array when doing the above initialization.
Then,you need a variable to add the sum of each roman number. So create
int sum=0;
And you need to loop the length of array times as you want to check each letter.
int i,len=strlen(romanNumerals);
for(i = 0;i < len;i++)
{
//body of for loop
}
string.h should be included in order to use strlen function which returns the length of a string.
Now,check each letter inside the body of the for loop using
if(romanNumerals[i]=='M')
sum=sum+1000;
else if(romanNumerals[i]=='C')
sum=sum+/*the corresponding value*/;
else if(...)
sum=sum+/*value*/;
//etc etc
And then at last,print sum.

Your best bet is to use the scanf function from stdio.h.
char str[3];
scanf("%s", str);
would store up to two characters from the standard input and the null terminator (\0) into the char array pointed at by str.

All other answers are correct, but keep in mind that if you just sum the input letters with a lookup (M=1000, C=100, X=10, V=5, I=1), having "MMMCMXCVIII" would mean 3000+100+1000+10+100+5+3 = 4218 and this is not what "MMMCMXCVIII" means in roman numerals (it actually means 3998 ).

For reasons explained in the link supplied by NSimon (see 1st comment) scanf() is not the best option when the input string length isn't known.
Other options are fgets() and getline(). The thing to remember is that a properly formed string is terminated by a null character - usually written '\0'. Hence if all else fails, you can always read char for char using the fgetc() function in a loop of some sort and stop when either your buffer is full or the '\0' is found.
So much for reading the array. When it comes to evaluating roman numerals, the best approach is to start at the back. Roman numerals have a (niot quite so simple) ordering:
I < V < X < L < C < D < M
Reading backwards you need to follow some straight forward rules:
The least significant packet is always last (i.e. IXL is wrong, it should be LIX = 59)
If X or V is preceeded by I then subract 1 otherwise add the value.
If L or C is preceeded by X then subtract 10 otherwise add the value.
If D or M is preceeded by C then subtract 100 otherwise add the value.
Note that M & D can only ever be preceeded by C or M. L & C can only be preceeded by X or C. X & V can only be preceeded by I or X. Anything else indicates a malformed number.
Thus working from the back it should be reasonably easy to obtain the correct value.

Related

How can I use sscanf to analyze string data?

How do I split a string into two strings (array name, index number) only if the string is matching the following string structure: "ArrayName[index]".
The array name can be 31 characters at most and the index 3 at most.
I found the following example which suppose to work with "Matrix[index1][index2]". I really couldn't understand how it does it in order to take apart the part I need to get my strings.
sscanf(inputString, "%32[^[]%*[[]%3[^]]%*[^[]%*[[]%3[^]]", matrixName, index1,index2) == 3
This try over here wasn't a success, what am I missing?
sscanf(inputString, "%32[^[]%*[[]%3[^]]", arrayName, index) == 2
How do I split a string into two strings (array name, index number) only if the string is matching the following string structure: "ArrayName[index]".
With sscanf, you don't. Not if you mean that you can rely on nothing being modified in the event that the input does not match the pattern. This is because sscanf, like the rest of the scanf family, processes its input and format linearly, without backtracking, and by design it fills input fields as they are successfully matched. Thus, if you scan with a format that assigns multiple fields or has trailing literal characters then it is possible for results to be stored for some fields despite a matching failure occurring.
But if that's ok with you then #gsamaras's answer provides a nearly-correct approach to parsing and validating a string according to your specified format, using sscanf. That answer also presents a nice explanation of the meaning of the format string. The problem with it is that it provides no way to distinguish between the input fully matching the format and the input failing to match at the final ], or including additional characters after.
Here is a variation on that code that accounts for those tail-end issues, too:
char array_name[32] = {0}, idx[4] = {0}, c = 0;
int n;
if (sscanf(str, "%31[^[][%3[^]]%c%n", array_name, idx, &c, &n) >= 3
&& c == ']' && str[n] == '\0')
printf("arrayName = %s\nindex = %s\n", array_name, idx);
else
printf("Not in the expected format \"ArrayName[idx]\"\n");
The difference in the format is the replacement of the literal terminating ] with a %c directive, which matches any one character, and the addition of a %n directive, which causes the number of characters of input read so far to be stored, without itself consuming any input.
With that, if the return value is at least 3 then we know that the whole format was matched (a %n never produces a matching failure, but docs are unclear and behavior is inconsistent on whether it contributes to the returned field count). In that event, we examine variable c to determine whether there was a closing ] where we expected to find one, and we use the character count recorded in n to verify that all characters of the string were parsed (so that str[n] refers to a string terminator).
You may at this point be wondering at how complicated and cryptic that all is. And you would be right to do so. Parsing structured input is a complicated and tricky proposition, for one thing, but also the scanf family functions are pretty difficult to use. You would be better off with a regex matcher for cases like yours, or maybe with a machine-generated lexical analyzer (see lex), possibly augmented by machine-generated parser (see yacc). Even a hand-written parser that works through the input string with string functions and character comparisons might be an improvement. It's still complicated any way around, but those tools can at least make it less cryptic.
Note: the above assumes that the index can be any string of up to three characters. If you meant that it must be numeric, perhaps specifically a decimal number, perhaps specifically non-negative, then the format can be adjusted to serve that purpose.
A naive example to get you started:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[] = "myArray[123]";
char array_name[32] = {0}, idx[4] = {0};
if(sscanf(str, "%31[^[][%3[^]]]", array_name, idx) == 2)
printf("arrayName = %s\nindex = %s\n", array_name, idx);
else
printf("Not in the expected format \"ArrayName[idx]\"\n");
return 0;
}
Output:
arrayName = myArray
index = 123
which will find easy not-in-the-expected format cases, such as "ArrayNameidx]" and "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP[idx]", but not "ArrayName[idx".
The essence of sscanf() is to tell it where to stop, otherwise %s would read until the next whitespace.
This negated scanset %[^[] means read until you find an opening bracket.
This negated scanset %[^]] means read until you find a closing bracket.
Note: I used 31 and 3 as the width specifiers respectively, since we want to reserve the last slot for the NULL terminator, since the name of the array is assumed to be 31 characters at the most, and the index 3 at the most. The size of the array for its token is the max allowed length, plus one.
How can I use sscanf to analyze string data?
Use "%n" to detect a completed scan.
array name can be 31 characters at most and the index 3 at most.
For illustration, let us assume the index needs to limit to a numeric value [0 - 999].
Use string literal concatenation to present the format more clearly.
char name[32]; // array name can be 31 characters
#define NAME_FMT "%31[^[]"
char idx[4]; //
#define IDX_FMT "%3[0-9]"
int n = 0; // be sure to initialize
sscanf(str, NAME_FMT "[" IDX_FMT "]" "%n", array_name, idx, &n);
// Did scan complete (is `n` non-zero) with no extra text?
if (n && str[n] == '\0') {
printf("arrayName = %s\nindex = %d\n", array_name, atoi(idx));
} else {
printf("Not in the expected format \"ArrayName[idx]\"\n");
}

Removing spaces in a string

I was trying to remove spaces of a string after scanning it. The program has compiled perfectly but it is not showing any output and the output screen just keeps getting shut down after scanning the string. Is there a logical error or is there some problem with my compiler(I am using a devc++ compiler btw).
Any kind of help would be appreciated
int main()
{
char str1[100];
scanf("%s",&str1);
int len = strlen(str1);
int m;
for (m=0;m<=len;){
if (&str1[m]==" "){
m++;
}
else {
printf("%c",&str1[m]);
}
m++;
}
return 0;
}
Edit : sorry for the error of m=1, I was just checking in my compiler whether that works or not and just happened to paste that code
Your code contains a lot of issues, and the behaviour you describe is very likely not because of a bug in the compiler :-)
Some of the issues:
Use scanf("%s",str1) instead of scanf("%s",&str1). Since str1 is defined as a character array, it automatically decays to a pointer to char as required.
Note that scanf("%s",str1) will never read in any white space because "%s" is defined as skipping leading white spaces and stops reading in when detecting the first white space.
In for (m=1;m<=len;) together with str1[m], note that an array in C uses zero-based indizes, i.e. str1[0]..str1[len-1], such that m <= len exceeds array bounds. Use for (m=0;m<len;) instead.
Expression &str1[m]==" " is correct from a type perspective, but semantically a nonsense. You are comparing the memory address of the mth character with the memory address of a string literal " ". Use str1[m]==' ' instead and note the single quotes denoting a character value rather than double quotes denoting a string literal.
Statement printf("%c",&str1[m]) passes the memory address of a character to printf rather than the expected character value itself. Use printf("%c",str1[m]) instead.
Hope I found everything. Correct these things, turn on compiler warnings, and try to get ahead. In case you face further troubles, don't hesitate to ask again.
Hope it helps a bit and good luck in experiencing C language :-)
There are many issues:
You cannot read a string with spaces using scanf("%s") , use fgets instead (see comments).
scanf("%s", &str1) is wrong anyway, it should be scanf("%s", str1);, str1 being already the address of of the string
for (m = 0; m <= len;) is wrong, it should be for (m = 0; m < len;), because otherwise the last character you will check is the NUL string terminator.
if (&str1[m]==" ") is wrong, you should write if (str1[m]==' '), " " does not denote a space character but a string literal, you need ' ' instead..
printf("%c", &str1[m]); is wrong, you want to print a char so you need str1[m] (without the &).
You should remove both m++ and put that into the for statement: for (m = 1; m < len; m++), that makes the code clearer.
And possibly a few more problems.
And BTW your attempt doesn't remove the spaces from the string, it merely displays the string skipping spaces.
There are a number of smaller errors here that are adding up.
First, check the bounds on your for loop. You're iterating from index 1 to index strlen(str1), inclusive. That's a reasonable thing to try, but remember that in C, string indices start from 0 and go up to strlen(str1), inclusive. How might you adjust the loop to handle this?
Second, take a look at this line:
if (&str1[m] == " ") {
Here, you're attempting to check whether the given character is a space character. However, this doesn't do what you think it does. The left-hand side of this expression, &str1[m], is the memory address of the mth character of the string str1. That should make you pause for a second, since if you want to compare the contents of memory at a given location, you shouldn't be looking at the address of that memory location. In fact, the true meaning of this line of code is "if the address of character m in the array is equal to the address of a string literal containing the empty string, then ...," which isn't what you want.
I suspect you may have started off by writing out this line first:
if (str1[m] == " ") {
This is closer to what you want, but still not quite right. Here, the left-hand side of the expression correctly says "the mth character of str1," and its type is char. The right-hand side, however, is a string literal. In C, there's a difference between a character (a single glyph) and a string (a sequence of characters), so this comparison isn't allowed. To fix this, change the line to read
if (str1[m] == ' ') {
Here, by using single quotes rather than double quotes, the right-hand side is treated as "the space character" rather than "a string containing a space." The types now match.
There are some other details about this code that need some cleanup. For instance, look at how you're printing out each character. Is that the right way to use printf with a character? Think about the if statement we discussed above and see if you can tinker with your code. Similarly, look at how you're reading a string. And there may be even more little issues here and there, but most of them are variations on these existing themes.
But I hope this helps get you in the right direction!
For loop should start from 0 and less than length (not less or equal)
String compare is wrong. Should be char compare to ' ' , no &
Finding apace should not do anything, non space outputs. You ++m twice.
& on %c output is address not value
From memory, scanf stops on whitespace anyway so needs fgets
int main()
{
char str1[100];
scanf("%s",str1);
int len = strlen(str1);
int m;
for (m=0;m<len;++m){
if (str1[m]!=' '){
printf("%c",str1[m]);
}
}
return 0;
}
There are few mistakes in your logic.
scanf terminates a string when it encounter any space or new line.
Read more about it here. So use fgets as said by others.
& in C represents address. Since array is implemented as pointers in C, its not advised to use & while getting string from stdin. But scanf can be used like scanf("%s",str1) or scanf("%s",&str[1])
While incrementing your index put m++ inside else condition.
Array indexing in C starts from 0 not 1.
So after these changes code will becames something like
int main()
{
char str1[100];
fgets(str1, sizeof str1 , stdin);
int len = strlen(str1);
int m=0;
while(m < len){
if (str1[m] == ' '){
m++;
}
else {
printf("%c",str1[m]);
m++;
}
}
return 0;
}

Identyfying prefix in the same string as a suffix

Eg-
maabcma is valid because it contains ma as a proper prefix as well as a proper suffix.
panaba is not.
How do I find out if a word is valid or not as above in C language?
I'm not very good at string operations. So, please help me out with a pseudocode.
Thanks in advance.
I'm completely lost. T=number of test cases.
EDIT: New code. My best code so far-
#include<stdio.h>
#include<string.h>
void main()
{
int i,T,flag=0;
int j,k,len=0;
char W[10],X[10];
scanf("%d",&T);
for(i=0;i<T;i++)
{
scanf("%s",W);
for(len=0;W[len]!='\0';len++)
X[len]=W[len];
X[len]='\0';
for(j=len-1;j>=0;j--)
for(k=0;k<len;k++)
{
if(X[k]!=W[j])
flag=0;
else if((j-k)==(len-1))
flag==1;
}
if (flag == 1)
printf("NICE\n");
else
printf("NOT\n");
}
}
Still not getting the proper results. Where am I going wrong?
The thing is you are only setting the value of flag if a match exists, otherwise you must set it to 0. because see, if I have:
pammbap
my prefix is pam and suffix is bap.
According to the final for loop,
p and a match so flag is set to 1.
but when it comes to b and m it does not become zero. Hence, it returns true.
First, void is not a valid return type for main, unless you are developing for Plan 9.
Second, you should get into the habit of checking the return value of scanf() and all input functions in general. You can't rely on the value of T if the user does not input a number, because T is uninitialised. On that same note, you shouldn't use scanf with an unbounded %s scan operation. If the user enters 20 characters, this isn't going to fit into the ten character buffer that you have. An alternative approach is to use fgets to get a whole line of text at once, or, to use a bounded scan operation. If your array fits 10 characters (including the null terminator) then you can use scanf("%9s", W).
Third, single-character variable names are often very hard to understand. Instead of W, use word, instead of T, use testCount or something similar. This means that someone looking at your code for the first time can more easily work out what each variable is used for.
Most importantly, think about the process in your head, and maybe jot it down on paper. How would you solve this problem yourself? As an example, starting with n = 1,
Take the first n characters from the string.
Compare it to the last n characters from the string
Do they match?
If yes, print out the first n characters as the suffix and stop processing.
If no, increment n and try again. Try until n is in the middle of the string.
There are a few other things to think about as well, do you want the biggest match? For example, in the input string ababcdabab, the prefix ab is also the suffix, but the same can be said about abab. In this case, you don't want to stop processing, you want to keep going even if you find a prefix, so, you should just store the length of the largest prefix that is also the suffix.
Second-most-importantly, running into hurdles like this is incredibly common when learning C, so don't let this put a dampener on your enthusiasm, just keep trying!

Read all the subsequent chars and transform into an int

I'm reading a txt file and getting all the chars that aren't space, transforming them to int using (int)c-'0' and that is working.
The problem is if the number has more than 1 digit, because I'm reading char by char.
How could I do to read like a sequence of chars, transform this sequence of chars into int?
I tried using a string, but when I try to pass this string to my other function, it treats each index as a number, but what I need is that the whole string is treated as one number.
Any ideas?
A convenient way to do the conversion is to read the whole number into a buffer (string) and then call atoi. Make triple sure that the string is properly null-terminated.
One solution, I won't say it's good or bad in your case since you don't provide any code, but you could do something like this: (pseudoish code)
int i;
int val = 0;
char *string = "5238785";
for (i = 0; i < strlen(string); i++) {
val = val * 10 + atoi(string[i]);
}
NOTE: I simplified it and you should do more string controls to make sure you don't go out of bounds etc. Make sure the string is NULL-terminated \0, but the concept is that you read one digit at the time, and just move what you've read so far "one step left" to fit next digit.

New to C: whats wrong with my program?

I know my way around ruby pretty well and am teaching myself C starting with a few toy programs. This one is just to calculate the average of a string of numbers I enter as an argument.
#include <stdio.h>
#include <string.h>
main(int argc, char *argv[])
{
char *token;
int sum = 0;
int count = 0;
token = strtok(argv[1],",");
while (token != NULL)
{
count++;
sum += (int)*token;
token = strtok(NULL, ",");
}
printf("Avg: %d", sum/count);
printf("\n");
return 0;
}
The output is:
mike#sleepycat:~/projects/cee$ ./avg 1,1
Avg: 49
Which clearly needs some adjustment.
Any improvements and an explanation would be appreciated.
Look for sscanf or atoi as functions to convert from a string (array of characters) to an integer.
Unlike higher-level languages, C doesn't automatically convert between string and integral/real data types.
49 is the ASCII value of '1' char.
It should be helpful to you....:D
The problem is the character "1" is 49. You have to convert the character value to an integer and then average.
In C if you cast a char to an int you just get the ASCII value of it. So, you're averaging the ascii value of the character 1 twice, and getting what you'd expect.
You probably want to use atoi().
EDIT: Note that this is generally true of all typecasts in C. C doesn't reinterpret values for you, it trusts you to know what exists at a given location.
strtok(
Please, please do not use this. Even its own documentation says never to use it. I don't know how you, as a Ruby programmer, found out about its existence, but please forget about it.
(int)*token
This is not even close to doing what you want. There are two fundamental problems:
1) A char* does not "contain" text. It points at text. token is of type char*; therefore *token is of type char. That is, a single byte, not a string. Note that I said "byte", not "character", because the name char is actually wrong - an understandable oversight on the part of the language designers, because Unicode did not exist back then. Please understand that char is fundamentally a numeric type. There is no real text type in C! Interpreting a sequence of char values as text is just a convention.
2) Casting in C does not perform any kind of magical conversions.
What your code does is to grab the byte that token points at (after the strtok() call), and cast that numeric value to int. The byte that is rendered with the symbol 1 actually has a value of 49. Again, interpreting a sequence of bytes as text is just a convention, and thus interpreting a byte as a character is just a convention - specifically, here we are using the convention known as ASCII. When you hit the 1 key on your keyboard, and later hit enter to run the program, the chain of events set in motion by the command window actually passed a byte with the value 49 to your program. (In the same way, the comma has a value of 44.)
Both of the above problems are solved by using the proper tools to parse the input. Look up sscanf(). However, you don't even want to pass the input to your program this way, because you can't put any spaces in the input - each "word" on the command line will be passed as a separate entry in the argv[] array.
What you should do, in fact, is take advantage of that, by just expecting each entry in argv[] to represent one number. You can again use sscanf() to parse each entry, and it will be much easier.
Finally:
printf("Avg: %d", sum/count)
The quotient sum/count will not give you a decimal result. Dividing an integer by another integer yields an integer in C, discarding the remainder.
In this line: sum += (int)*token;
Casting a char to an int takes the ASCII value of the char. for 1, this value is 49.
Use the atoi function instead:
sum += atoi(token);
Note atoi is found in the stdlib.h file, so you'll need to #include it as well.
You can't convert a string to an integer via
sum += (int)*token;
Instead you have to call a function like atoi():
sum += atoi (token);
when you cast a char (which is what *token is) to int you get its ascii value in C - which is 49... so the average of the chars ascii values is in fact 49. you need to use atoi to get the value of the number represented

Resources