I'm making an appointment calendar program with c. My program adds an new appointment with user inputted command: "A 'description' 'mm' 'dd' 'hh'"
Where description is a string with a maximum of 20 characters, mm is months, dd is days and hh is hours. Months, days and hours can be 1 or 2 characters long.
I have tried to implement readInput function which splits the input string by spacebar and returns a char array which contains: [description, mm, dd, hh] so I can easily get:
desc = array[1];
month = array[2];
day = array[3];
hour = array[4];
Implementing this function was harder than I thought and I have failed miserably. I don't want pointers, just a basic char array containing strings. How should I implement this? Below is my main function.
int main()
{
struct Calendar c;
c.numOfAppointments = 0;
while (true) {
char str[30];
printf("Command: ");
scanf("%[^\n]%*c", str);
if (str[0] == 'A')
{
char command = readInput(str); /*implement this */
}
else if (str[0] == 'L')
{
printCalendar(c);
}
else if (str[0] == 'Q')
{
printf("Exiting program...");
break;
}
}
}
Say I input: A dentist 4 20 10
the returned array should be: ["dentist","4","20","10"]
Implementing this function was harder than I thought and I have failed miserably.
Don't be so hard on yourself... you're learning. We learn to program mainly through our mistakes :-)
I don't want pointers, just a basic char array containing strings.
Ah, so, there's your problem: Will it be an array of characters, or an array of strings?
A string in C is a pointer to a sequence of characters in memory ending with a \0.
An "array of strings" is an array of pointers!
What you could do is:
Read your line into a proper array of characters.
Place '\0' at appropriate places in this array, to indicate the end of line components.
Have a second array, e.g. const char * array_of_fields[4], whose elements are strings.
or
Have a struct { const char* description, month, day, hour; }
and then
Set the elements of the second array, or the elements of the struct, to point to the appropriate positions within the character array.
Use fgets(str, strlen(str), stdin) to read in your string. The next step is is to parse the string. As your input consist of a variable description followed by a somewhat variable date time format. The way to parse is to start at the end to find the separator sep between description and month which would be the 3rd last space (n = 2). You now know whatever is before sep is "A " prefix and description, and everything after is the date time. You can use strptime(3) to parse the date time:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int rindexn(const char *s, char c, size_t n) {
int i = strlen(s);
if(!i) return -1;
for(i--; i >= 0; i--) {
if(s[i] == c) {
if(!n) break;
n--;
}
}
return i >= 0 ? i : -1;
}
int main() {
const char *str = "A dentist 4 20 10";
// parse
if(!strncmp(str, "A ", 2)) {
printf("A space prefix missing");
return 1;
}
int sep = rindexn(str, ' ', 2);
if(sep == -1) {
printf("sep not found\n");
return 1;
}
struct tm tm;
char *end = strptime(str + sep + 1, "%m %d %H", &tm);
if(!end) {
pritnf("cannot parse date time\n");
return 1;
} else if(*end) {
printf("extra data after hour\n");
return 1;
}
// convert to whatever format you decide
printf("description = \"%.*s\", month = %d, day = %d, hour = %d",
(int) sep - 2, str + 2, tm.tm_mon, tm.tm_mday, tm.tm_hour);
}
which gives the following output:
description = "dentist", month = 3, day = 20, hour = 10
Related
So I'm slowly continuing learning C. And now, I have a task, to read data from a file and sort it.
File data:
House naming 1 30 300
House naming 2 45 450
.......
House naming 10 5 120
So, first value: House naming, can be any naming like Empire state building
The second value is: House address (I chose only integer values)
The third value is: Age of a building
The fourth value is: Kilowatt-hour/year
Programm must take data from a file -> Print it out -> Sort(how? see below) -> print out again, sorted.
Sorting:
kwh < 200 - sustainable building,
kwh < 300 && age < 40 - needs renovation,
kwh > 300 && age > 40 - set for demolition.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include "input.h"
int main(void) {
int kwh;
int age;
char building[SIZE];
int addr;
char buff[SIZE];
FILE *fi;
// opening the files and checking if it succeeded
fi = fopen(F_INPUT, "r");
if (fi == NULL) {
printf("Error opening input file \"%s\"", F_INPUT);
exit(EXIT_INPUT_FAIL);
}
while (fgets(buff, sizeof(buff), fi) != NULL) {
sscanf(buff, "%s %d %d %d", building, &addr,&age,&kwh);
if (kwh < 200) {
puts(buff);
printf("Sustainable\n");
} else
if (kwh < 300 && age < 40) {
puts(buff);
printf("Needs renovation\n");
} else
if (kwh > 300 && age > 40) {
puts(buff);
printf("IN DEMOLITION LIST\n");
}
}
/* close the files when they're not needed anymore */
fclose(fi);
return 0;
}
I've combined a few steps to make it a bit easier, reads data -> outputs already marked 1) Sustainable, 2) Needs renovation, 3) set for demolition.
The problem is somewhere in the while loop and I think it's in sscanf function.
In my logic, if I am not mistaken, it must read a string from a file, using logic(look at sscanf and input file): char value, integer, integer, integer.
Programm reads the file, outputs the data, but marks all buildings as sustainable.
What you suggest to read more carefully or what logic is better to choose for reading multiple strings.
Output:
House naming 1 30 300
Sustainable
House naming 2 45 450
Sustainable
........
House naming 10 5 120
Sustainable
Reading the line from the file into a string via fgets() is a good first step as OP has done.
Can "House naming" include digits? like "Stdio 54"?
Yea, it can include digits and can not. If I am right, the task says nothing about namings.
The next part is tricky as there is not a unique separator between the house name and the following 3 integers.
One approach would be to find the 3 trailing integers and then let the remaining beginning text as the house name.
while (fgets(buff, sizeof(buff), fi) != NULL) {
int address, age, power;
char *p = buff + strlen(buff); // start as buff end
p = reverse_scan_int(buff, p, &power);
p = reverse_scan_int(buff, p, &age);
p = reverse_scan_int(buff, p, &address);
if (p) {
*p = '\0';
trim(buff); // remove leading trailing white-space
printf("house_name:'%s', address:%d age:%d power:%d\n", buff, address,
age, power);
} else {
printf("Failed to parse '%s'\n", buff);
}
}
Now all we need is reverse_scan_int(). Sample untested code idea:
#include <ctype.h>
#include <stdbool.h>
char *reverse_scan_int(const char *begin, char *one_past, int *i) {
if (one_past == NULL) {
return NULL;
}
// is...() functions work best with unsigned char
unsigned char *p = (unsigned char *) one_past;
// Skip trailing whitespace;
while (p > begin && isspace(p[-1])) {
p--;
}
// Skip digits;
bool digit_found = false;
while (p > begin && isdigit(p[-1])) {
p--;
digit_found = true;
}
if (!digit_found)
return NULL;
if (p > begin && (p[-1] == '-' || p[-1] == '+')) {
p--;
}
*i = atoi(p); // More roubust code would use `strtol()`, leave for OP.
return (char *) p;
}
There are lots of ways to trim a string including this one.
Your problem is tricky to solve with sscanf() because there is no explicit separator between the house name and the 3 numeric fields. %s is inappropriate: it parses a single word. In your program, sscanf() actually fails to convert the numbers and returns 1 for all lines, leading to undefined behavior when you compare the numeric values that are actually uninitialized.
Here is a modified version using the %[ conversion specification:
#include <stdio.h>
#include <stdlib.h>
#define F_INPUT "input.txt"
#define EXIT_INPUT_FAIL 1
int main(void) {
char buff[256];
char building[100];
int addr, age, kwh;
FILE *fi;
// opening the files and checking if it succeeded
fi = fopen(F_INPUT, "r");
if (fi == NULL) {
printf("Error opening input file \"%s\"", F_INPUT);
exit(EXIT_INPUT_FAIL);
}
while (fgets(buff, sizeof(buff), fi) != NULL) {
/* parse the building name upto and excluding any digit,
then accept 3 integral numbers for the address, age and power */
if (sscanf(buff, "%99[^0-9]%d%d%d", building, &addr, &age, &kwh) != 4) {
printf("parsing error: %s", buff);
continue;
}
if (kwh < 200) {
puts(buff);
printf("Sustainable\n");
} else
if (kwh < 300 && age < 40) {
puts(buff);
printf("Needs renovation\n");
} else
if (kwh > 300 && age > 40) {
puts(buff);
printf("IN DEMOLITION LIST\n");
}
// allocate structure with building details and append it to the list or array of buildings
}
/* close the files when they're not needed anymore */
fclose(fi);
// sort the list or array and print it
// free the list or array
return 0;
}
i want to read these data and put them to a array of struct but it does not work
#include<stdio.h>
struct book {
char bookName[50];
char authorName[50];
long price;
int year;
}
main() {
FILE *data;
data=fopen("library.txt", "r");
if (data == NULL) {
printf("File Could not be opened!\n");
}
else {
struct book myBook;
struct book books[20];
int n=0;
while (!feof(data))
{
fscanf(data,"%s***%s***%d***%d\n",&myBook.bookName,&myBook.authorName,&myBook.price,&myBook.year);
books[n]=myBook;
n++;
}
int i;
for(i=0;i<n;i++){
printf("%s - %s - %d - %d \n",books[i].bookName,books[i].authorName,books[i].price,books[i].year);
}
}
}
and output is
C - b - 0 - 232159429
programing***Fatemeh - b - 0 - 232159429
Kazemi***15000***1391 - b - 0 - 232159429
C - b - 0 - 232159429
programs***Ali - b - 0 - 232159429
Ahmadpour***20000***1392 - b - 0 - 232159429
Programing***Mona - b - 0 - 232159429
Ghassemi***25000***1389 - b - 0 - 232159429
C - b - 0 - 232159429
programing - b - 0 - 232159429
(advanced)***Sara - b - 0 - 232159429
Hamidi***40000***1385 - b - 0 - 232159429
but my real data is
C programing***Fatemeh Kazemi***15000***1391
Cprograms***Ali Ahmadpour***20000***1392
Programing***Mona Ghassemi***25000***1389
C programing (advanced)***Sara Hamidi***40000***1385
what should i do?
it looks fscanf only works with spaces but i need to use *** to seperate my data
This program reads your data in the current format and produces the output as '-' delimited entries (as in the printf statement you provided):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXBUF 500
int parse_string(char* s,char* a[]);
struct book {
char bookName[50];
char authorName[50];
long price;
int year;
};
int main() {
FILE *data;
char buf[MAXBUF];
char *sp, *words[MAXBUF];
int nw;
data=fopen("library.txt", "r");
if (data == NULL) {
printf("File Could not be opened!\n");
}
else {
struct book myBook;
struct book books[20];
int n=0;
// Read each line into buf and parse it into words,
// assign words into structure fields
while((sp = fgets(buf, MAXBUF, data))!= NULL){
nw=parse_string(buf, words);
// If number of words different than number of
// fields in the structure exit with an error
if (nw!=4){
printf("Error - number of parsed words does not match number of fields in the structure!\n");
exit(1);
}
// Assign values, convert strings to long and int
strncpy(myBook.bookName, words[0], strlen(words[0])+1);
strncpy(myBook.authorName, words[1], strlen(words[1])+1);
myBook.price = atol(words[2]);
myBook.year = atoi(words[3]);
// Add to book array
books[n] = myBook;
n++;
}
// Print
int i;
for(i=0;i<n;i++){
printf("%s - %s - %ld - %d \n",books[i].bookName,books[i].authorName,books[i].price,books[i].year);
}
}
}
/* Function to parse a line of input into an aray of words */
/* s - pointer to the char array (line) to be parsed
* a - array of pointers to parsed elements
* returns number of elements in a*/
int parse_string(char* s, char* a[])
{
int nw,j;
a[0] = strtok(s,"*\t\n\r\v\f");
nw = 1;
while((a[nw]= strtok(NULL,"*\t\n\r\v\f"))!=NULL)
nw++;
return nw;
}
Like suggested in the comments, this program uses fgets to read the file line at a time. It then uses a parsing function to parse each line into words based on given delimiters. The parsing function is small and uses strtok and hardcoded delimiter set. Based on your input, it does not use the space as a delimiter and instead uses the *. It allows for other delimiters like reasonably new lines and maybe not as reasonably tabs.
Next step is assignment of each word to its field in the book structure. This is preceded by a check whether the number of words return from the parsing function (nw) is equal to to the current number of fields). Finally, if it is - it assigns the members with any necessary conversions to myBook and adds this entry to book array.
Some improvements that can be left out as an exercise would be enabling command line argument with input file name rather than hardcoding it. Writing the output to a file would also be good in which case output file would be the second command line argument. Finally, as mentioned in the comments you could and should provide some input size checking against the sizes of the arrays you are using.
Don't use fscanf(). The error checking is too difficult or incomplete.
while (!feof(data)) does not insure the the following read will be successful.
// while (!feof(data)){
// fscanf(data,"%s***%s***%d***%d\n",....
Use fgets() to read a line of file input and then parse.
size_t n = 0;
// Work with an ample sized buffer
char buf[sizeof (struct book) * 2];
while (n < 20 && fgets(buf, sizeof buf, data)) {
Now parse the data looking for "***"
char *sep[3];
sep[0] = strstr(buf, "***");
if (sep[0] == NULL) break;
sep[1] = strstr(sep[0] + 3, "***");
if (sep[1] == NULL) break;
sep[2] = strstr(sep[1] + 3, "***");
if (sep[2] == NULL) break;
Let us pre-fill myBook with zeros - useful for debugging and insure null characters for the strings.
struct book myBook;
Insure separators are not too far apart
if (sep[0] - buf >= sizeof myBook.bookName) break;
memcpy(myBook.bookName, buf, sep[0] - buf); //
if (sep[1] - sep[0] - 3 >= sizeof myBook.authorName) break;
memcpy(myBook.authorName, sep[0] + 3, sep[1] - sep[0] - 3);
Use atol() or ...
myBook.price = atol(sep[1] + 3);
... strtol(), or sscanf() for more error checking. Maybe check for valid year values?
char *endptr;
errno = 0;
myBook.year = strtol(sep[2] + 3, &endptr, 10);
if (sep[2] + 3 == endptr) break;
if (errno) break;
if (myBook.year < year_MIN || myBook.year > year_MAX) break;
Ok, code made it
books[n] = myBook;
n++;
}
but i need to use *** to separate my data
If "*" and "**" never occur, code could use the following which has less error checking. Always check the return values of input functions.
while (n < 20 && fgets(buf, sizeof buf, data)) {
if (sscanf(buf, "%49[^*]***%49[^*]***%ld***%d",
myBook.bookName, myBook.authorName, &myBook.price, &myBook.year) != 4) {
break; // badly formatted data
}
books[n] = myBook;
n++;
}
I'm using C to read in an external text file. The input is not great and would look like;
0PAUL 22 ACACIA AVENUE 02/07/1986RN666
As you can see I have no obvious delimeter, and sometimes the values have no space between them. However I do know how long in character length each value should be when split. Which is as follows,
id = 1
name = 20
house number = 5
street name = 40
date of birth = 10
reference = 5
I've set up a structure I want to hold this information in, and have tried using fscanf to read in the file.
However I find something along the lines of just isn't doing what I need,
fscanf(file_in, "%1d, %20s", person.id[i], person.name[i]);
(The actual line I use attempts to grab all input but you should see where I'm going...)
The long term intention is to reformat the input file into another output file which would be made a little easier on the eye.
I appreciate I'm probably going about this all the wrong way, but I would hugely appreciate it if somebody could set me on the right path. If you're able to take it easy on me in regard to an obvious lack of understanding, I'd appreciate that also.
Thanks for reading
Use fgets to read each line at a time, then extract each field from the input line. Warning: no range checks is performed on buffers, so attention must be kept to resize buffers opportunely.
For example something like this (I don't compile it, so maybe some errors exist):
void copy_substr(const char * pBuffer, int content_size, int start_idx, int end_idx, char * pOutBuffer)
{
end_idx = end_idx > content_size ? content_size : end_idx;
int j = 0;
for (int i = start_idx; i < end_idx; i++)
pOutBuffer[j++] = pBuffer[i];
pOutBuffer[j] = 0;
return;
}
void test_solution()
{
char buffer_char[200];
fgets(buffer_char,sizeof(buffer_char),stdin); // use your own FILE handle instead of stdin
int len = strlen(buffer_char);
char temp_buffer[100];
// Reading first field: str[0..1), so only the char 0 (len=1)
int field_size = 1;
int filed_start_ofs = 0;
copy_substr(buffer_char, len, filed_start_ofs, filed_start_ofs + field_size, temp_buffer);
}
scanf is a good way to do it, you just need to use a buffer and call sscanf multiple times and give the good offsets.
For example :
char buffer[100];
fscanf(file_in, "%s",buffer);
sscanf(buffer, "%1d", person.id[i]);
sscanf(buffer+1, "%20s", person.name[i]);
sscanf(buffer+1+20, "%5d", person.street_number[i]);
and so on.
I feel like it is the easiest way to do it.
Please also consider using an array of your struct instead of a struct of arrays, it just feels wrong to have person.id[i] and not person[i].id
If you have fixed column widths, you can use pointer arithmetic to access substrings of your string str. if you have a starting index begin,
printf("%s", str + begin) ;
will print the substring beginning at begin and up to the end. If you want to print a string of a certain length, you can use printf's precision specifier .*, which takes a maximum length as additional argument:
printf("%.*s", length, str + begin) ;
If you want to copy the string to a temporary buffer, you could use strncpy, which will generate a null terminated string if the buffer is larger than the substring length. You could also use snprintf according to the above pattern:
char buf[length + 1];
snprintf(buf, sizeof(buf), "%.*s", length, str + begin) ;
This will extract leading and trailing spaces, which is probably not what you want. You could write a function to strip the unwanted whitespace; there should be plenty of examples here on SO.
You could also strip the whitespace when copying the substring. The example code below does this with the isspace function/macro from <ctype.h>:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int extract(char *buf, const char *str, int len)
{
const char *end = str + len;
int tail = -1;
int i = 0;
// skip leading white space;
while (str < end && *str && isspace(*str)) str++;
// copy string
while (str < end && *str) {
if (!isspace(*str)) tail = i + 1;
buf[i++] = *str++;
}
if (tail < 0) tail= i;
buf[tail] = '\0';
return tail;
}
int main()
{
char str[][80] = {
"0PAUL 22 ACACIA AVENUE 02/07/1986RN666",
"1BOB 1 POLK ST 01/04/1988RN802",
"2ALICE 99 WEST HIGHLAND CAUSEWAY 28/06/1982RN774"
};
int i;
for (i = 0; i < 3; i++) {
char *p = str[i];
char id[2];
char name[20];
char number[6];
char street[35];
char bday[11];
char ref[11];
extract(id, p + 0, 1);
extract(name, p + 1, 19);
extract(number, p + 20, 5);
extract(street, p + 25, 34);
extract(bday, p + 59, 10);
extract(ref, p + 69, 10);
printf("<person id='%s'>\n", id);
printf(" <name>%s</name>\n", name);
printf(" <house>%s</house>\n", number);
printf(" <street>%s</street>\n", street);
printf(" <birthday>%s</birthday>\n", bday);
printf(" <reference>%s</reference>\n", ref);
printf("</person>\n\n");
}
return 0;
}
There's a danger here, however: When you access a string at a certain position str + pos you should make sure that you don't go beyond the actual string length. For example, you string may be terminated after the name. When you access the birthday, you access valid memory, but it might contain garbage.
You can avoid this problem by padding the full string with spaces.
I'm new to low level programming and have been stuck with the following problem:
I get a string in the following format:
?cmd=ASET&<hour>&<minute>
where the hour and minute values always consist of 2 decimal numbers.
So an example of the string that can be received is:
"?cmd=ASET&08&30"
I am trying to write an if statement that recognizes that the string starts with "?cmd=ASET" and changes two global variables called minute and hour to the values in the String. I've been trying to do this with strtok(), but have not had any luck so far. So the global layout of my if statement would be:
if (String starts with "?cmd=ASET") {
minute = value found in the string;
hour = value found in the string;
}
I would really appreciate any help.
Try something like this, where cmd is a char * or char [] type variable. Note, strncmp() is safer than strcmp(). In general, in C programming, you want to use the variants of functions that limit the length, to avoid stack overflow attacks and other security risks. And since string to numeric functions can fail if given bad input it is better to use a form where you can check their status, which is why atoi() and atol() are not recommended. sscanf() allows status to be checked as does strtol() so they are both acceptable.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
main()
{
char *string = "?cmd=ASET&12&30";
#define ASET_CMD "?cmd=ASET"
int hour = 0, minute = 0;
if (strncmp(string, ASET_CMD, strlen(ASET_CMD)) == 0) {
if (sscanf(string + strlen(ASET_CMD), "&%d&%d", &hour, &minute) != 2) {
printf("Couldn't parse input string");
exit(EXIT_FAILURE);
}
}
printf("hour: %d, minute: %d\n", hour, minute);
return(EXIT_SUCCESS);
}
$ cc -o prog prog.c
$ ./prog
hour: 12, minute: 30
If sscanf() is available for OP, consider:
unsigned hour, minute;
int n;
int cnt = sscanf(buffer, "?cmd=ASET&%2u&%2u%n", &hour, &minute, &n);
if (cnt == 2 && buffer[n] == 0) Success();
else Failure();
cnt will have the value of 2 if the prefix matches and 2 numbers where found.
The n detects if any addtional characters exist in the string.
there is a function atoi() which returns integer from string.
You can parse string like that
char string[16];
strcpy(string, "?cmd=ASET&08&30");
if (String starts with "?cmd=ASET") {
hour = atoi(string+10);
minute = atoi(string+13);
}
where +10 is position for hour and +13 for minute.
here is a working example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
int hour, minute;
char string[16];
strcpy(string, "?cmd=ASET&08&30");
/* Check if string contains ?cmd=ASET */
if (strstr(string, "?cmd=ASET") != NULL)
{
/* Parse minute and hour */
hour = atoi(string+10);
minute = atoi(string+13);
/* Print output */
printf("Minute: %02d \nHour: %02d\n", minute, hour);
}
}
Suppose I have a street address stored as a char[]. Examples of valid values:
1600 Pennsylvania Ave
1 Infinite Loop
221 Baker Street
As you can see, the house number can be of any length.
In C, what is an efficient way of separating the house number into its own int? I'm thinking I need to write a while loop to check for each char c if isdigit(c), but I don't know if I'm on the right track here in terms of implementation.
You can use strtok to break up the string into tokens and use isdigit() to figure out if that token is numeric.
#include <string.h>
#include <stdio.h>
int main()
{
const char str1[80] = "1600 Pennsylvania Ave";
int houseNumber = 0;
const char s[2] = " ";
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
if (isdigit(str1[0])) {
houseNumber = atoi (token);
}
token = strtok(NULL, s);
}
return(0);
}
Alternatively, you can use sscanf to read the entire string and automatically parse everything:
#include <string.h>
#include <stdio.h>
int main()
{
const char str1[80] = "1600 Pennsylvania Ave";
int houseNumber = 0;
char streetName[50];
char streetExt[20];
sscanf (str1,"%d %s %s", &houseNumber, streetName, streetExt);
return(0);
}
This last method depends on the format of the strings being exactly the same in all cases, meaning that it's always a number followed by 2 strings. The strtok method will be a little more fault tolerant if there's more other stuff.
Consider the following solution:
#include <stdio.h>
#include <string.h>
int main(void)
{
char address[255];
char * ptr;
int number;
char strnumber[100];
char strstreet[255];
// ask adress
printf("Please, enter the addres: ");
// put end of string replacing newline
fgets(address, 255, stdin);
ptr = strchr(address, '\n');
if(ptr)
{
*ptr = '\0';
}
else
{
address[254] = '\0';
}
// try to read whole number from the beggining of the string
if( 1 == sscanf(address, "%d", &number) )
{
// make number as a string (if it is needed)
sprintf(strnumber, "%d", number);
// take streat to separate string
ptr = strchr(address + strlen(strnumber), ' '); // find the firs space
if( ptr )
{
strcpy(strstreet, ptr + 1); // +1 just to skip the found space
}
}
else
{ // if no number at the beginning of address string
number = 0;
strnumber[0] = '\0';
strstreet[0] = '\0';
}
// show the results
printf("You have entered a string:\n%s\n", address);
printf("The found number is:\n%d\n", number);
printf("The found number as a string:\n%s\n", strnumber);
printf("The address without number is:\n%s\n", strstreet);
}
I would use strstr and atoi like this
char someAddress[80] = "1600 Pennsylvania Ave";
char* p = strstr(someAddress, " ");
if (p)
{
*p = 0; // Terminate string, i.e. cheat for a moment
int number = atoi(someAddress);
*p = " "; // Restore someAddress
}
else
{
// Handle illegal format in someAddress
}
This method shall only be used when you know it is safe to modify someAddress for a short period.
This is one situation with the numbers first, where it is much easier just to use a simple pointer and an if statement to parse the line:
#include <stdio.h>
#define ADDL 64
int main (void) {
char address[ADDL] = {0};
char street[16] = {0};
while (fgets (address, ADDL-1, stdin) != NULL)
{
char *ap = address;
char *sp = street;
while (*ap >= '0' && *ap <= '9') /* while the char is a number */
{
*sp = *ap++; /* copy to street number */
sp++;
}
*sp = 0; /* null-terminate */
printf (" Address: %s Number : %s\n\n", address, street);
}
return 0;
}
Output
$ ./bin/split_address < dat/houses.txt
Address: 1600 Pennsylvania Ave
Number : 1600
Address: 1 Infinite Loop
Number : 1
Address: 221 Baker Street
Number : 221
Note: the printf statement above makes use to the embedded newline at the end of address rather than stripping it as you would normally do. Also note that if you want the number as an integer, long, or unsigned, simply call atoi, strtol or strtoul on street.