I want to split this string
kim-tae-yeon
and put them into different variables, like this:
data[1] = "kim" data[2] = "tae" data[3] = "yeon"
but I only split the string without store them to these variable.
How can I do this?
Here is my code:
char buff[] = "kim-tae-yeon";
int i = 0;
char *p = strtok (buff, "-");
char *data[3];
while (p)
{
data[i++] = p;
p = strtok (NULL, "-");
}
for (i = 0; i < 3; i++)
{
printf ("%s\n", &data[i]);
}
return 0;
}
Your program works well. The error comes by the fact that you are passing to printf &data[i] but datais an array of pointers (char *[]), which means each entry of the array is a pointer (char *). You want pass to printf a string, data[i].
This is the output you want:
for (i = 0; i < 3; i++)
{
printf("data[%i] = %s\n", i+1, data[i]);
}
As in the comment were said, there is no data[3].
The array starts at data[0], this is a default of C.
You can still have the output
data[1] = kim
data[2] = tae
data[3] = yaeon
by adding 1 to i,
but this output doesn't represent your actual data array.
This is wrong:
printf("%s\n", &data[i]);
The %sformat specifier requires a char* but you provided a char **(pointer to pointer to char). data[i] is already a char *, therefore you need:
printf("%s\n", data[i]);
If you had compiled with all warnings enabled (-Wall option with gcc) your compile would have told you this.
If you're ready to limit the length of the substrings, this can be solved much easier and less scary (strtok() is scary, come on!) using plain old sscanf():
const char buff[] = "kim-tae-yeon";
char data[3][32];
if (sscanf(buff, "%31[^-]-%31[^-]-%31[^-]", data[0], data[1], data[2]) == 3)
{
printf("parts are '%s', '%s' and '%s'\n", data[0], data[1], data[2]);
}
The format specifier, which is repeated three times with dashes in-between, is %31[^-], this means "collect at most 31 non-dash characters". The 31 makes sure there's room to terminate in our 32-character buffers.
It's a bit non-DRY with the buffer size repeated in the format string, the easiest fix for this is to generate the format string at run-time using snprintf(), but that obscures the issue so I didn't do that.
Something like this can work. It instead uses strcpy to copy over the string being pointed at, in this case buffer, to the space in data[i].
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRSIZE 50
#define NUMWORDS 3
int
main(void) {
char buff[] = "kim-tae-yeon";
char data[NUMWORDS][STRSIZE];
char *buffer;
int i;
buffer = strtok(buff, "-");
i = 0;
while (buffer != NULL) {
strcpy(data[i], buffer);
printf("data[%i] = %s\n", i+1, data[i]);
buffer = strtok(NULL, "-");
i++;
}
return 0;
}
Related
This question already has an answer here:
How to use sscanf in loops?
(1 answer)
Closed 4 years ago.
I used sscanf to segment one string taken from the input and store every token in a structure. The problem is that sscanf only reads the first word of the string and doesn't move ahead to the next word, printing the same token over and over. Here's the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define dim 30
typedef struct string {
char* token[dim];
}string;
int main() {
string* New = (string *)malloc(dim*sizeof(string));
char* s;
char buffer[dim];
int i = 0, r = 0, j = 0;
s = (char*)malloc(sizeof(char*));
printf("\nString to read:\n");
fgets(s, dim, stdin);
printf("\nThe string is: %s", s);
while(sscanf(s, " %s ", buffer) != EOF) {
New->token[i] = malloc(dim*sizeof(char));
strcpy(New->token[i], buffer);
printf("\nAdded: %s", New->token[i]);
++i;
}
}
For example, if i give "this is a string" as an input, sscanf will only get the word "this" multiple times without moving on to the next word.
You need to increment the pointer of the source sscanf() reads from, so that it won't read from the same point, again and again.
Furthermore, the memory dynamically allocated for s by you didn't make any sense. It was too less in any case. By the call to fgets() later in the code I can see you meant to say s = malloc(dim * sizeof(char));, so I went ahead and fixed that.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define dim 30
typedef struct string {
char* token[dim];
} string;
int main() {
string* New = malloc(dim*sizeof(string));
char* s;
char buffer[dim];
int i = 0;
s = malloc(dim * sizeof(char));
fgets(s, dim, stdin);
printf("The string is: %s\n", s);
char* ptr = s;
int offset;
while (sscanf(ptr, "%s%n", buffer, &offset) == 1) {
ptr += offset;
New->token[i] = malloc(strlen(buffer) + 1);
strcpy(New->token[i], buffer);
printf("Added: %s\n", New->token[i]);
++i;
}
// do work
for(int j = 0; j < i; ++j)
free(New->token[i]);
free(New);
free(s);
return 0;
}
Output:
The string is: this is a string
Added: this
Added: is
Added: a
Added: string
PS: I am not sure about the schema of structures you have in mind, maybe you need to spend a moment or two, thinking about that twice; I mean whether your design approach is meaningful or not.
PPS: Unrelated to your problem: Do I cast the result of malloc? No!
Edit: As #chux said, " " in " %s%n" of sscanf() serves no purpose. I changed it to "%s%n".
Moreover, in order to reserve exactly as much memory as needed (which is the thing to do, when dealing with dynamic memory allocation), New->token[i] = malloc(dim*sizeof(char)); was changed to New->token[i] = malloc(strlen(buffer) + 1);.
Let's say I have the following string stored in char *m;
char *m = "K: someword\r\n";
The m will be inputed by the user so the user will write in the console:
K: someword\r\n
The someword can have different length, while K: \r\n will always be the same.
Now my question is, which is the best way after I read this input to extract someword from it and save it into a new char* variable?
Use sscanf() like this:
#include <stdio.h>
int main (void)
{
char buffer [50], k, return_car, new_line;
int n = sscanf ("K: someword\r\n", "%c: %s%c%c", &k, buffer, &return_car, &new_line);
printf ("The word is \"%s\". sscanf() read %d items.\n", buffer, n);
return 0;
}
Output:
The word is "someword". sscanf() read 4 items
Since both the substrings we aren't interested in ("K: " and "\r\n") are of fixed length, you can do this:
char *s;
size_t len = strlen(m);
s = malloc(len);
strcpy(s, m + 3);
s[len - 4] = 0;
printf("%s\n", s);
free(s);
Note that I declared a new char * variable to copy to since m is in read-only memory, and that robust code would handle the case where malloc failed and returned NULL.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *m = "K: someword\r\n";
const size_t someword_len = strlen(&m[3]);
char *someword = malloc(someword_len);
if (someword == NULL) { fprintf(stderr, "Malloc error\n"); abort(); }
memcpy(someword, &m[3], someword_len - 2);
someword[someword_len - 1] = '\0';
puts(someword);
free(someword);
}
You assume that string m always starts with "K: " (that's 3 characters) and ends with "\r\n" (that's two characters).
I believe strlen(m) will be faster then strchr(m, '\r') or strrchr(m, '\r') on most platforms
After you have the length of the string, using memcpy instead of strcpy will be faster.
Remember to null terminate your string
Remember to handle errors.
I'm trying to read a buffer, copy all the non-alphabetical characters and dump it into another buffer.
The problem I'm getting is that whenever I encounter a non numerical character, it won't copy anything more.
I have tried to try to detect the blank spaces, use an auxiliary buffer...
int main(void)
{
char buffer[] = "103 PLUS 1";
char buffer2[] = "a";
int i, number;
memset(buffer2, 0, sizeof (buffer2));
size_t length = strlen(buffer);
fprintf(stdout,"Buffer initially: %s \n", buffer);
fprintf(stdout,"Buffer2 initially: %s \n", buffer2);
for(i=0; i<length; i++)
{
if (number = isalpha(buffer[i]) == 0)
{
strncpy(&buffer2[i], &buffer[i], 1);
}
}
fprintf(stdout, "Copied buffer is: %s \n", buffer2);
return 0;
}
Thanks in advance.
Your code leaves the first element of buffer2 to be 0, indicating the end of the C-string. In fact, the index of same characters should differ in buffer and buffer2, because characters must be consistent within a C-string, but some characters are not copied.
It's unnecessary to initialise buffer with "a". Use {0} instead.
You don't need to use variable number.
Refined code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char buffer[80] = "103 PLUS 1";
char buffer2[80] = {0};
int i, j = 0;
size_t length = strlen(buffer);
fprintf(stdout,"Buffer initially: %s \n", buffer);
fprintf(stdout,"Buffer2 initially: %s \n", buffer2);
for(i = 0; i < length; i++)
{
if (isalpha(buffer[i]))
{
strncpy(&buffer2[j++], &buffer[i], 1);
}
}
fprintf(stdout, "Copied buffer is: %s \n", buffer2);
return 0;
}
Output:
Buffer initially: 103 PLUS 1
Buffer2 initially:
Copied buffer is: PLUS
When you skip copying a character over, buffer2 is left w/ whatever was originally in that position, which seems to be 0 (but may not always be), which is why printing it out looks like no other characters were copied. In fact, they were, but the skipped character is interpreted as the null termination of that string.
But worse, you never allocate space for buffer2: you let the compiler do it, which means you aren't really allowed to modify that space. As with the above, you might be getting away with it, but it is undefined behavior, and could actually crash your program.
If i have a string that contains 10X15. And i want to separate the 10 and 15. Would the following code be correct. I am concerned about the second part of the code, is putting "NULL" there the right thing to do.
char * stringSixrows = strtok(stringSix[0], "X");
char * stringSixcollumns = strtok(NULL, "NULL");
//I put the second null there cause its the end of string, im not sure if its right though.
I'd say the "canonical" way to obtain the "pointer to the remaining string" is:
strtok(NULL, "")
strtok searches for any of the delimiters in the provided string, so if you don't provide any delimiters, it cannot find anything and thus only stops at the end of the input string.
example
#include <stdio.h>
#include <string.h>
int main(void){
char stringSix[] = "10X15";
char *stringSixrows = strtok(stringSix, "X");
char *stringSixcolumns = strtok(NULL, "X");
printf("%s, %s\n", stringSixrows, stringSixcolumns);
return 0;
}
another way
char stringSix[] = "10X15";
char stringSixrows[3];
char stringSixcolumns[3];
char *p;
if(NULL!=(p = strchr(stringSix, 'X')))
*p = '\0';
else {
printf("invalid format\n");
return -1;
}
strcpy(stringSixrows, stringSix);
strcpy(stringSixcolumns, p+1);
printf("%s, %s\n", stringSixrows, stringSixcolumns);
const char *stringSix = "10X15";
int stringSixrows;
int stringSixcolumns;
if(2==sscanf(stringSix, "%dX%d", &stringSixrows, &stringSixcolumns))
printf("%d, %d\n", stringSixrows, stringSixcolumns);
You can use strtol to convert the string to numbers as well as seek to the next string. Below code safely does the intended operation:
char stringSix[] = "10X15";
char * pEnd;
long firstNumber = strtol (stringSix,&pEnd, 10);
pEnd = strtok(pEnd, "");
long secondNumber = strtol (pEnd,&pEnd, 10);
I am a newbie in c programming language and I have a university tutorial assignment that is related with working with chars(I wont be graded for this assignment) where you have to count words, I have to compile and submit my answers in an online web environment where my code will run against test cases that are not visible to me.here is my assignment:
Write the function 'wc' which returns a string containing formatted as follows: "NUMLINES NUMWORDS NUMCHARS NUMBYTES" .
Whitespace characters are blanks, tabs (\t) and new lines (\n). A character is anything that is not whitespace. The given string is null-char (\0) terminated.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* wc(char* data) {
char* result ;
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
char* empty=NULL;
while(strstr(data,empty)>0){
numWords=1;
for (i = 0; i < sizeof(data); i++) {
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
this code will give me the correct output result but I am missing something here at least the test tells me that.
You've got a very serious error:
char* result;
...
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
This is not allowed in C. You need to allocate sufficient memory for the string first. Declare result as a large enough static array, or use malloc if you've covered that in your course.
e.g.
char buf[100]; // temporary buffer
sprintf(buf, "%d %d %d %d", numLine, numWords, numChars, numBytes);
char *result = malloc(strlen(buf) + 1); // just enough for the string
strcpy(result, buf); // store the string
return result;
What if you have this input?
Two Words.
You have to count the transitions between whitespace/non-whitespace, not just count spaces.
Also, I'm pretty sure strstr(data,NULL) will not do anything useful.
You also appear to be missing the \t for tab in your white space checker, and you're not correctly checking when you're in or out of a word. You can use the boolean type bool for this defined in stdbool.h for this.
Source code of wc unix command:
http://www.gnu.org/software/cflow/manual/html_node/Source-of-wc-command.html
All test cases handled.
1) sizeof is wrong:
Instead of sizeof operator you need to use strlen() in for loop, like:
for (i = 0; i < strlen(data); i++)
^ not sizeof
sizeof(data) returns only size of data pointer address that is 4. Because you are to read all char in data[] you need strlen() that will return length of data[] (or number of chars in data[])
2) memory error:
Next Error I can notice there is no memory allocated for result. it declare like:
char* result ;
and No memory allocate! and you are writing using sprintf that cause undefined behavior of your code
3) while(strstr(data,empty)>0) is wrong
strstr() search position of a string in to other you empty string is NULL , CHECK:
char *strstr(const char *s1, const char *s2);
you strstr() always returns data, Why are you calling this? I believe you don't need this while() loop.
I improved you code upto some extend as below, There was only three error as I mentioned above now corrected(to understand read comments), You basic algo is correct:
#define SIZE 256 // added size macro
char* wc(char* data)
char* result = malloc(SIZE*sizeof(char)); //(2) allocated memory for result
int numLine ;
int numWords ;
int numChars ;
int i;
int numBytes =strlen(data);
numWords=1;
// (3) remove while loop
for (i = 0; i < strlen(data); i++) { //(1) change size
if(data[i]=='\n'){
numLine++;
}
if(data[i]==' ' ){
numWords++;
}
if(data[i]!=' '){
numChars++;
}
}
sprintf(result, "%d %d %d %d", numLine, numWords, numChars, numBytes);
return result;
}
int main(){
printf("\nresult: %s\n", wc("q toei lxlckmc \t \n ldklkjjls \n i \t nn "));
return 1;
}
Output:
result: 2 14 28 41