I want to parse a string into a note and octave. For example if the user inputs "A#4", (A#)-note that will be stored in (char n) and (4)- octave that will be stored in (char o). Why am I getting blanked line instead of 4 as output after A#?
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main()
{
string src = get_string();
char *n;
char *o;
char *note = "ABCDEFG#b";
char *octave = "12345678";
o = strtok(src, note);
n = strtok(src, octave);
printf("%s\n", n);
printf("%s\n", o);
}
Output:
A#
Can you please point to error and suggest a solution?
strtok is not the function you want to use in this instance.
When you call it, it alters the string, replacing the character that matches the deliminator with a NUL so you'll lose the character you're looking for as the note. The second time you call it with src, the string will appear empty and it won't find anything - you're meant to call it on subsequent times with the first parameter set to NULL so that it knows you're searching for the next token in the same string.
You might want to use strspn which counts the number of characters that match your set (ie note) or strpbrk that finds the first character that matches.
Or you could traverse the string yourself and use strchr like this
char *pos;
for(pos=src;*pos!='\0';pos++)
{
if(strchr(note,*pos))
{
// *pos is a note character
}
}
Whatever you use, you'll need to build a new string based on your results as the original string won't have space to put NUL terminators inside to separate out the two parts you're looking for.
Related
I am reading a .txt file which contains data in a random form i.e. it contains integers and strings mixed in it.
Sample .txt file:
this is a 22 string 33 sorry222 stack33ing
still yysi288 2nd line
I want to read the file and differentiate all valid string i.e. which do not contain integers concatinated with them. And store those strings in an array.
Any leads on how to differentiate?
You can use #include <ctype.h> for that purpose.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int checkString( const char s[] ) {
unsigned char c;
while ( ( c = *s ) && ( isalpha( c ) || isblank( c ) ) ) ++s;
return *s == '\0';
}
void printNonNumericWords(char str[]) {
int init_size = strlen(str);
char delim[] = " ";
char *ptr = strtok(str, delim);
while(ptr != NULL)
{
if (checkString(ptr))
printf("'%s'\n", ptr);
ptr = strtok(NULL, delim);
}
printf("\n");
}
Call function like this.
printNonNumericWords(this is a 22 string 33 sorry222 stack33ing");
First: I can´t write the programm for you. It is your task to do and beside this i can´t even change things on your code or at least suggest to alter, because you are not providing any code. I can give you only a dusty leading algorithm for this case:
All the words you might see, are not valid strings in the file. It is only one string containing white space characters between each sequence of characters which appear for you as one word or separated string, but it doesn´t.
You have to get the whole string from the file first and store it into an char array, lets name it source, using fgets():
#include <stdio.h>
FILE *input;
char source[200];
input = fopen("text.txt","r");
fgets(source, 200, input);
After that you need to make those "words" separated strings by transport each of the characters of the source string, one after another, to other char arrays and quit writing the characters to them as soon as the space character or the NUL-byte after the last word is provided in the source string. Don´t forget to make a Nul-Byte (\n) terminating each string.
Thereafter you check each, now valid and separated string, if it either is a string that contains numbers or a string without any number.
I have tried this code to separate my Str[] string into 2 string, but my problem is "I want to separate John(name) as string and 100(marks) as integer",How can I do it, any suggestion?
#include <stdio.h>
#include <string.h>
void main()
{
char Str[] = "John,100";
int i, j, xchange;
char name[50];
char marks[10];
j = 0; xchange = 0;
for(i=0; Str[i]!='\0'; i++){
if(Str[i]!=',' && xchange!=-1){
name[i] = Str[i];
}else{
xchange = -1;
}
if(xchange==-1){
marks[j++] = Str[i+1];
}
}
printf("Student name is %s\n", name);
printf("Student marks is %s", marks);
}
How to separate "John,100" into 2 strings?
There are three common approaches:
Use strtok() to split the string into individual tokens. This will modify the original string, but is quite simple to implement:
int main(void)
{
char line[] = "John,100;passed";
char *name, *score, *status;
/* Detach the initial part of the line,
up to the first comma, and set name
to point to that part. */
name = strtok(line, ",");
/* Detach the next part of the line,
up to the next comma or semicolon,
setting score to point to that part. */
score = strtok(NULL, ",;");
/* Detach the final part of the line,
setting status to point to it. */
status = strtok(NULL, "");
Note that if you change char line[] = "John,100"; then status will be NULL, but the code is otherwise safe to run.
So, in practice, if you required all three fields to exist in line, it would be sufficient to ensure the last one was not NULL:
if (!status) {
fprintf(stderr, "line[] did not have three fields!\n");
return EXIT_FAILURE;
}
Use sscanf() to convert the string. For example,
char line[] = "John,100";
char name[20];
int score;
if (sscanf(line, "%19[^,],%d", name, &score) != 2) {
fprintf(stderr, "Cannot parse line[] correctly.\n");
return EXIT_FAILURE;
}
Here, the 19 refers to the number of chars in name (one is always reserved for the end-of-string nul char, '\0'), and [^,] is a string conversion, consuming everything except a comma. %d converts an int. The return value is the number of successful conversions.
This approach does not modify the original string, and it allows you to try a number of different parsing patterns; as long as you try them the most complex one first, you can allow multiple input formats with very little added code. I do this regularly when taking 2D or 3D vectors as inputs.
The downside is that sscanf() (all functions in the scanf family) ignores overflow. For example, on 32-bit architectures, the largest int is 2147483647, but scanf functions will happily convert e.g. 9999999999 to 1410065407 (or some other value!) without returning an error. You can only assume the numerical inputs are sane and within the limits; you cannot verify.
Use helper functions to tokenise and/or parse the string.
Typically, the helper functions are something like
char *parse_string(char *source, char **to);
char *parse_long(char *source, long *to);
where source is a pointer to the next character in the string to be parsed, and to is a pointer to where the parsed value will be stored; or
char *next_string(char **source);
long next_long(char **source);
where source is a pointer to a pointer to the next character in the string to be parsed, and the return value is the value of the extracted token.
These tend to be longer than above, and if written by me, then quite paranoid about the inputs they accept. (I want my programs to complain if their input cannot be reliably parsed, rather than silently produce garbage.)
If the data is some variant of CSV (comma-separated values) read from a file, then the proper approach is a different one: instead of reading the file line by line, you read the file token by token.
The only "trick" is to remember the separator character that ended the token (you can use ungetc() for this), and use a different function to (read and ignore the rest of the tokens in the current record, and) consume the newline separator.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've been trying to learn C programming by reading a textbook, but am confused about how strings and substrings work.
I have an idea of what strings and substrings are from java, but can't figure out the syntax in C.
Here's a question from the book that I thought might be easy, but I can't get it.
Write and test a function hydroxide that returns a 1 for true if its string argument ends in the substring OH.
It recommends testing the function with KOH and NaCl.
Also, how would I remove and add letters at the end of the string?
Like, if for some reason I wanted to change NaCl to NaOH?
Any help and explanations would be really appreciated.
ETA:
I guess what I'm most confused on is how to make the program look at the last two letters in the string and compared them to OH.
I'm also not sure how to pass strings to functions.
String is a sequence of characters that ends with special null-terminated character '\0'. If there is no \0, functions that work with string won't stop until the \0 symbol is found. This character may happen in any place after the end of pseudo string (I mean a string without \0) and only then stop.
The following example shows the necessity of this null-terminated character:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[] = "Hello!";
printf("original string:\n%s\n\n", string);
memset(string, '-', 5);
printf("memset doesn't affect the last two symbols: '!' and '\\0':\n%s", string);
memset(string, '-', 6);
printf("\n\nmemset doesn't affect the last symbol: '\\0':\n%s\n\n", string);
memset(string, '-', 7);
printf("memset affects all symbols including null-terminated one:\n%s", string);
return 0;
}
/* OUTPUT:
original string:
Hello!
memset doesn't affect the last two characters: '!' and '\0':
-----!
memset doesn't affect the last character: '\0':
------
memset affects all characters including null-terminated one:
-------#↓#
*/
Substring is a char sequence that is in a string. It may be less or equal to the string.
Suppose, "NaOH" is a string. Then substring may be: "N", "a", "O", "H", "Na", "aO", "OH", "NaO", "aOH", "NaOH". To find whether substring is in the string or not you can use strstr function. It's prototype is char * strstr ( char * str1, const char * str2 );.
This code shows this function's results:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *ptrCh = NULL;
ptrCh = strstr("hello", "h");
printf("ptrCh: %p\n", ptrCh);
printf("%s\n\n", ptrCh);
ptrCh = strstr("hello", "z");
printf("ptrCh: %p\n", ptrCh);
printf("%s\n\n", ptrCh);
return 0;
}
/* OUTPUT:
ptrCh: 00403024
hello
ptrCh: 00000000
(null)
*/
As for the first printf, it prints characters beginning from the position of 'h' and when it reaches null-terminated character, which is next after 'o', it stops, exactly as in previous program.
To make your program more interactive, you can declare array and then a pointer to it. Array size must be enough to store the longest formula. Suppose, 100 will be enough:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[100] = {0};
char *ptr = &buf[0];
scanf("%s", ptr);
// printf() gets a pointer as argument
printf("%s\n", ptr);
// printf() gets also a pointer as argument.
// When you pass arrays name without index to a function,
// you pass a pointer to array's first element.
printf("%s", buf);
return 0;
}
And as for rewriting letters in the end of the string. Here is a small program that does it. Pay attention at comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[100] = {0};
char formula[100] = {0};
char compound[100] = {0};
char *ptr = &buf[0];
char *pFormula = &formula[0];
char *pCompound = &compound[0];
printf("Enter formula: ");
scanf("%s", pFormula);
printf("Enter chemical compound: ");
scanf("%s", pCompound);
// Copying the first chemical elements without the last
// several that will be replaced by another elements.
strncpy(ptr, pFormula, strlen(pFormula) - strlen(pCompound));
// Adding new compound to the first elements.
// Function also adds a null-terminated character to the end.
strncat(ptr, pCompound, strlen(pCompound));
printf("The new chemical compound is: ");
printf("%s", ptr);
return 0;
}
/* OUTPUT:
Enter formula: NaOH
Enter chemical compound: Cl
The new chemical compound is: NaCl
*/
In C, we use null-terminated strings. That is the "invisible", 0 value. Not ASCII "0", but the zero value, like 8-bit 0x00. You can represent it in literal text with '\0' or "\0" or unquoted 0, however, in a literal string it is redundant because most functions like strcmp() or strstr() or strcat() all expect and work with null terminated strings. Null char is the stops sign for the C standard string functions.
One easy way to implement this with C library calls is to test for existence of the substring and then test that substring's length, which verify it is at end of string.
Assume buf is some big string buffer, char buf[1024] and char *temp is a temporary variable.
temp = strstr(buf, "OH") returns the pointer to "OH" if exists in buf at any offset.
strlen(temp) Get length of temp, if at end of string, it will be 2 (doesn't include null terminator), so if the original string is "OHIO" or "SOHO" it wont match because it'll be 4 and 3 respectively.
The above is the core of the code, not the full robust implementation. You need to check for valid return values, etc.
char buf[1024];
char *temp;
strcpy(buf, "NaOH");
if((temp = strstr(buf, "OH")) != 0)
{
// At this point we know temp points to something that starts with "OH"
// Now see if it is at the end of the string
if(strlen(temp) == 2)
return true; // For C99 include stdbool.h
return false;
}
You could get obscure, and check for the null terminator directly, will be a smidge quicker. This code is safe as long as it is inside the if() for strstr(), otherwise never do this if you don't know a string is a least N characters long.
if(temp[2] == '\0')
return true; // For C99 include stdbool.h
As far as appending to a string, read the docs on strcat. Keep in mind with strcat, you must have enough space already in the buffer you are appending into. It isn't like C++ std::string or Java/C# string where those will dynamically resize as needed. In C, you get to do all of that yourself.
I am very new in C, I have little idea about sprintf but I can't fulfill my requirement.
I have a char * variable which contains string like below :
date=2013-12-09 time=07:31:10 d_id=device1 logid=01 user=user1 lip=1.1.1.1 mac=00:11:22:33:44:55 cip=2.2.2.2 dip=3.3.3.3 proto=AA sport=22 dport=11 in_1=eth1 out_1=
I want an output as
2013-12-09#07:31:10#device1#01#user1#1.1.1.1#00:11:22:33:44:55#2.2.2.2#3.3.3.3#AA#22#11#eth1##
if some value is null after = it should print ## in sequence.
I am not going to give you exact code but I will give you some links that will help you.
strchr :: You can use this find the position of '=' in the string.
Now, copy the string after the position of '=' till you find a 'space'.
Whenever you will find a 'space', write a '#' in the buffer.
Keep doing this, till you encounter a '\0'. Write '##' to buffer when you have encountered '\0'
Append that with a '\0'.
Ex:: C function strchr - How to calculate the position of the character?
example by use strtok, strchr, sprintf
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
const char *data = "date=2013-12-09 time=07:31:10 d_id=device1 logid=01 user=user1 lip=1.1.1.1 mac=00:11:22:33:44:55 cip=2.2.2.2 dip=3.3.3.3 proto=AA sport=22 dport=11 in_1=eth1 out_1=";
char *work = strdup(data);//make copy for work
char *output = strdup(data);//allocate for output
char *assignment; //tokenize to aaa=vvv
size_t o_count = 0;//output number of character count
for(assignment=strtok(work, " "); assignment ;assignment=strtok(NULL, " ")){
o_count += sprintf(output + o_count, "%s#", strchr(assignment, '=')+1);
}
printf("%s", output);
free(work);
free(output);
return 0;
}
This is my Mystr value:
others:0.01 penalty:0.02 pdi:0.03 pdp:0.04 interest:0.05
principal:0.06 cbu:0.07 savings:0.08 bankcharge:0.09 grt:0.10
My desired output:
others:0.01
penalty:0.02
pdi:0.03
pdp:0.04
interest:0.05
principal:0.06
cbu:0.07
savings:0.08
bankcharge:0.09
grt:0.10
I want this to be assigned to a different variable. How do I do this?
The tool in C for this is strtok(GNU Manual, SUS V2 Spec). You call strtok the first time with your string and delimiter set. Then, for subsequent portions, call strtok with NULL and the delimiter set and it will keep searching from where it left off.
#include <string.h>
#include <stdio.h>
int main(void) {
char x[] = "others:0.01 penalty:0.02 pdi:0.03 pdp:0.04 interest:0.05 principal:0.06 cbu:0.07 savings:0.08 bankcharge:0.09 grt:0.10";
char toPrint[sizeof(x) * 2];
char *a;
strcpy(toPrint,strtok(x," "));
strcat(toPrint,"\n");
while ((a=strtok(NULL," ")) != NULL) {
strcat(toPrint,a);
strcat(toPrint,"\n");
}
fputs(toPrint,stdout);
}
Prints
others:0.01
penalty:0.02
pdi:0.03
pdp:0.04
interest:0.05
principal:0.06
cbu:0.07
savings:0.08
bankcharge:0.09
grt:0.10
Note that strtok modifies the original array. At the end of the program, the x array contains "1\02\03\04". All the delimiters have been overwritten by zeros. Also note that two consecutive delimiters in the string will cause strtok to yield an empty string "" for the (missing) value.
If you were writing code by Python, you would be lucky to use split().
In C, you can use strtok http://www.cplusplus.com/reference/cstring/strtok/