Switching numbers inside string - c

I got a string, that inside it has:
2#0.88315#1#1.5005#true#0.112 and it keep going...
I need to switch every number thats 2 or bigger, to 1,
so I wrote this :
for (i = 0 ; i < strlen(data) ; i++)
{
if (data[i] >= 50 && data[i] <= 57) // If it's a number
{
data[i] = '1'; // switch it to one
while (data[i] >= 48 && data[i] <= 57)
{
i++;
}
}
}
The problem is, that it makes numbers like 0.051511 as 1.111111 too...
Because it doesnt look at a double as one number, but every number seperatly...
How can I do it ?
Thanks

To clarify the question since it is unclear, you want to have the following input:
"2#0.88315#1#1.5005#true#0.112"
To be modified to be the following:
"1#0.88315#1#1#true#0.112"
Your problem is that you need to parse each number into a float value to do any sort of comparison. Either this, or you will need to manually parse it by checking for a '.' character. Doing it manually is rigid, error-prone and unnecessary because the C standard library provides functions which can help you.
Since this is homework, I'll give you some tips on how to approach this problem instead of the actual solution. What you should do is try to write a solution with these steps and if you get stuck, edit the original question with the code you wrote, where it is failing and why you think it is failing.
Your first step is to tokenise the input into the following:
"2"
"0.88315"
"1"
"1.5005"
"true"
"0.112"
This can be done by iterating through the string and either splitting it or using the pointer after which a '#' character occurs. Splitting the string can be done with strtok. However, strtok will split the string by modifying it which is not necessarily needed in our case. The simpler method is simply to iterate through the string and stop each time after a '#' character is reached. The input would then be tokenised to the following:
"2#0.88315#1#1.5005#true#0.112"
"0.88315#1#1.5005#true#0.112"
"1#1.5005#true#0.112"
"1.5005#true#0.112"
"true#0.112"
"0.112"
Some of these substrings do not start with a string which represents a float. You will need to determine which of them do. To do this, you can attempt to parse the front of each string as a float. This can be done with sscanf. After parsing the floats, you will be able to do the comparison you want to.
You are trying to modify the string into a different length so when replacing a float value by a '1', you need to check the length of the original value. If it is longer than 1 character, you will have to shift the subsequent characters forward. For example:
"3.423#1"
If you parsed the first token and found it to be > 2, you would replace the first character with a '1'. This result in:
"1.423#1"
You then still need to delete the rest of that token by shifting the rest of the string down to get:
"1#1"

It looks like you're comparing a char and an int in your if statements.
You should figure out why this matters and compensate for it.

You're comparing the characters in the string one at a time. If you need to consider everything between the "#" symbols as one number, this won't work. Try to get these numbers into an array, cast them to a double, and then do your comparison against 2.

Related

Integer to pointer type conversion

int count_words(string word)
{
string spaces = "";
int total_words = 1;
int i, j = 0 ;
for (i = 0; i < strlen(word); i++)
{
strcpy(spaces, word[i]);
if (strcmp(spaces, " ") == 0)
{
total_words = total_words + 1;
}
}
return total_words;
}
I am trying to make a function in c that gets the total number of words, and my strategy is to find the number of spaces in the string input. However i get an error at strcpy about integer to ptrtype conversion,. I cant seem to compare the 2 strings without getting the error. Can someone explain to me whats how the error is happening and how I would go about fixing it. The IDE is also suggesting me to add an ampersand beside word[i] but it then makes a segmentation fault output
You need to learn a little more about the distinction between characters and strings in C.
When you say
strcpy(spaces, word[i]);
it looks like you're trying to copy one character to a string, so that in the next line you can do
if (strcmp(spaces, " ") == 0)
to compare the string against a string consisting of one space character.
Now, it's true, if you're trying to compare two strings, you do have to call strcmp. Something like
if (spaces == " ") /* WRONG */
definitely won't cut it.
In this case, though, you don't need to compare strings. You're inspecting your input a character at a time, so you can get away with a simple character comparison instead. Get rid of the spaces string and the call to strcpy, and just do
if (word[i] == ' ')
Notice that I'm comparing against the character ' ', not the string " ". Using == to compare single characters like this is perfectly fine.
Sometimes, you do have to construct a string out of individual characters, "by hand", but when you do, it's a little more elaborate. It would look like this:
char spaces[2];
spaces[0] = word[i];
spaces[1] = '\0';
if (strcmp(spaces, " ") == 0)
...
This would work, and you might want to try it to be sure, but it's overkill, and there's no reason to write it that way, except perhaps as a learning exercise.
Why didn't your code
strcpy(spaces, word[i]);
work? What did the error about "integer to pointer conversion" mean? Actually there are several things wrong here.
It's not clear what the actual type of the string spaces is (more on this later), but it has space for at most 0 characters, so you're not going to be able to copy a 1-character string into it.
It's also not clear that spaces is even writable. It might be a constant, meaning that you can't legally copy any characters into it.
Finally, strcpy copies one string to another. In C, although strings are arrays, they're usually referred to as pointers. So strcpy accepts two pointers, one to the source and one to the destination string. But you passed it word[i], which is a single character, not a string. Let's say the character was A. If you hadn't gotten the error, and if strcpy had tried to do its job, it would have treated A as a pointer, and it would have tried to copy a string from address 65 in memory (because the ASCII value of the character A is 65).
This example shows that working with strings is a little bit tricky in C. Strings are represented as arrays, but arrays are second-class citizens in C. You can't pass arrays around, but arrays are usually referred to by simple pointers to their first element, which you can pass around. This turns out to be very convenient and efficient once you understand it, but it's confusing at first, and takes some getting used to.
It might be nice if C did have a built-in, first-class string type, but it does not. Since it does not, C programmers myst always keep in mind the distinction between arrays and characters when working with strings. That "convenient" string typedef they give you in CS50 turns out to be a bad idea, because it's not actually convenient at all -- it merely hides an important distinction, and ends up making things even more confusing.

C - scanf to pull a number in quotes only after a specific sequence of characters

Say I have a string like this:
Hello World - this is a line of textCOLOR="4"
and this string is stored in buf[1000]
As you can see this string has a color tag in the format of COLOR="n". The number is what needs to be pulled (it can be between 1 and 56) and assigned to an int variable. I'd like for this tag to be able to be anywhere in the string.
I can run the following code to extract the color value:
int colorNumber = 1; //default value
if (scanf(buf, "%*[^\"]\"%2d[^\"]\"", &colorNumber)) {
// work with number
}
and that works fine, but if the string were to contain a number or quote in it then the scanf would fail to produce the number.
I've tried a few variations of my second scanf argument, but those didn't work. I tried "%*[^\"]COLOR=\"%2d[^\"]\"" but that doesn't seem to work at all.
I've looked through the man pages for scanf, but I couldn't find what I was looking for in there either.
Perhaps scanf is not the right tool for this? I'm willing to try other libraries/functions if necessary.
try
if (sscanf(buf, "%*[^C]COLOR=\"%d", &colorNUM) == 1)
The reason your attempted "%*[^\"]COLOR"... format didn't work is that the %*[\"] matches everything up to the ", skipping past the COLOR, so will then fail to match COLOR. The above will fail if there's another C somwhere else in the string before COLOR, however. To avoid that you're probably better off using strstr, possibly in a loop if COLOR might appear multiple places.
for (const char *p = buf; p = strstr(p, "COLOR"); ++p) {
if (sscanf(p, "COLOR=\"%d", &colorNum) == 1) {
// found a color number
Note also, trying to match characters after the %d is pointless as regardelss of whether they match or not, the returned values will be the same, so there's no way to tell. If you want to ensure there's a " after the number, you need something like
int end = 0;
if (sscanf(p, "COLOR=\"%d\"%n", &colorNum, &end), end > 0)
by checking that %n wrote something to end, you're also checking that everything before the %n matched correctly.

How to read an array and analyse the input

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.

Sscanf not returning what I want

I have the following problem:
sscanf is not returning the way I want it to.
This is the sscanf:
sscanf(naru,
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]",
&jokeri, &paiva1, &keskilampo1, &minlampo1, &maxlampo1,
&paiva2, &keskilampo2, &minlampo2, &maxlampo2, &paiva3,
&keskilampo3, &minlampo3, &maxlampo3, &paiva4, &keskilampo4,
&minlampo4, &maxlampo4, &paiva5, &keskilampo5, &minlampo5,
&maxlampo5, &paiva6, &keskilampo6, &minlampo6, &maxlampo6,
&paiva7, &keskilampo7, &minlampo7, &maxlampo7);
The string it's scanning:
const char *str = "city;"
"2014-04-14;7.61;4.76;7.61;"
"2014-04-15;5.7;5.26;6.63;"
"2014-04-16;4.84;2.49;5.26;"
"2014-04-17;2.13;1.22;3.45;"
"2014-04-18;3;2.15;3.01;"
"2014-04-19;7.28;3.82;7.28;"
"2014-04-20;10.62;5.5;10.62;";
All of the variables are stored as char paiva1[22] etc; however, the sscanf isn't storing anything except the city correctly. I've been trying to stop each variable at ;.
Any help how to get it to store the dates etc correctly would be appreciated.
Or if there's a smarter way to do this, I'm open to suggestions.
There are multiple problems, but BLUEPIXY hit the first one — the scan-set notation doesn't follow %s.
Your first line of the format is:
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
As it stands, it looks for a space separated word, followed by a [, a ^, a ;, and a ] (which is self-contradictory; the character after the string is a space or end of string).
The first fixup would be to use scan-sets properly:
"%[^;]%[^;]%[^;]%[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
Now you have a problem that the first %[^;] scans everything up to the end of string or first semicolon, leaving nothing for the second %[;] to match.
"%[^;]; %[^;]; %[^;]; %[^;]; %f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
This looks for a string up to a semicolon, then for the semicolon, then optional white space, then repeats for three items. Apart from adding a length to limit the size of string, preventing overflow, these are fine. The %f is OK. The following material looks for an odd sequence of characters again.
However, when the data is looked at, it seems to consist of a city, and then seven sets of 'a date plus three numbers'.
You'd do better with an array of structures (if you've worked with those yet), or a set of 4 parallel arrays, and a loop:
char jokeri[30];
char paiva[7][30];
float keskilampo[7];
float minlampo[7];
float maxlampo[7];
int eoc; // End of conversion
int offset = 0;
char sep;
if (fscanf(str + offset, "%29[^;]%c%n", jokeri, &sep, &eoc) != 2 || sep != ';')
...report error...
offset += eoc;
for (int i = 0; i < 7; i++)
{
if (fscanf(str + offset, "%29[^;];%f;%f;%f%c%n", paiva[i],
&keskilampo[i], &minlampo[i], &maxlampo[i], &sep, &eoc) != 5 ||
sep != ';')
...report error...
offset += eoc;
}
See also How to use sscanf() in loops.
Now you have data that can be managed. The set of 29 separately named variables is a ghastly thought; the code using them will be horrid.
Note that the scan-set conversion specifications limit the string to a maximum length one shorter than the size of jokeri and the paiva array elements.
You might legitimately be wondering about why the code uses %c%n and &sep before &eoc. There is a reason, but it is subtle. Suppose that the sscanf() format string is:
"%29[^;];%f;%f;%f;%n"
Further, suppose there's a problem in the data that the semicolon after the third number is missing. The call to sscanf() will report that it made 4 successful conversions, but it doesn't count the %n as an assignment, so you can't tell that sscanf() didn't find a semicolon and therefore did not set &eoc at all; the value is left over from a previous call to sscanf(), or simply uninitialized. By using the %c to scan a value into sep, we get 5 returned on success, and we can be sure the %n was successful too. The code checks that the value in sep is in fact a semicolon and not something else.
You might want to consider a space before the semi-colons, and before the %c. They'll allow some other data strings to be converted that would not be matched otherwise. Spaces in a format string (outside a scan-set) indicate where optional white space may appear.
I would use strtok function to break your string into pieces using ; as a delimiter. Such a long format string may be a source of problems in future.

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!

Resources