I am trying to read a text file using input redirection, ./program < file.txt, and the file I made looks like this:
Country\tSport\tGender\tMedal\n
America\tCycling\tMens\tGold\n
New Zealand\tSwimming\tWomens\tSilver\n
India\tBadminton\tMens\tbronze\n
Which just reads some random data, in according to the first row with 4 columns, headed Country, Sport, Gender and Medal.
I also inserted \t and \n to make the file more readable, but the file actually has tabs and newlines in it.
I am trying to read each line of that file, and store them in an array of strings, which I have declared as:
char *records[ROWS][COLUMNS];
I would like the array of strings, records to look something like:
{{"Country", "Sport", "Gender", "Medal"}, {"America", "Cycling", "Mens", "Gold"},
{"New Zealand", "Swimming", "Womens", "Silver"}, {"India", "Badminton", "Mens", "Bronze"}}
So far I have just been using scanf to read the lines, like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS 1000
#define COLS 30
#define MAX_CH 50
int
main(int argc, char *argv[]) {
char *records[ROWS][COLS];
char country[MAX_CH];
char sport[MAX_CH];
char gender[MAX_CH];
char medal[MAX_CH];
while (scanf("%s\t%s\t%s\t%s\n", country, sport, gender, medal) == 4) {
printf("%s %s %s %s\n", country, sport, gender, medal);
}
return 0;
}
I know this will not work as the country name New Zealand has a space between both strings, and my scanf wil only read the first four characters. My method of scanf will also not be effective because it only works for 4 columns.
Is there a way I can use getchar() instead to do this? I'm just not sure how to use getchar to analyse each character in the input stream, and convert the necessary characters to strings depending on the tabs and newlines.
Pseudo code with getChar():
while (char = getChar()) is not 'EOF': // EOF = End of file
if char is not '\t' and char is not '\n'
save into current string
else if char is '\t'
terminate current string
increment column index
else if char is '\n'
terminate current string
increment row index
Edit:
The problem with getChar() is that you only know how long the string will be once you reach the next tab.
So you either have to iterate a first time to know the length of the string and then allocate an appropriate amount of memory, or you need to always allocate a safe amount of memory (your max string length).
Then in both options you can use strcat() to concatenate strings, but you can also access a char in a char* or char[] (String) by its index:
char string[] = "MINE"; // string[0] -> 'M'
string[0] = 'N'; // string -> "NINE"
// with dynamic memory allocation
char *string = (char*) malloc(5*sizeof(char));
string[0] = 'N'; // string -> "N"
getchar can be used to read into the rows and columns.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define ROWS 1000
#define COLS 30
#define MAX_CH 50
void print_array(char str[][COLS][MAX_CH], int nrows, int ncols, int col[], int reorder);
void sort_array(char str[][COLS][MAX_CH], int nrows, int ncols, int col[]);
int main( int argc, char *argv[])
{
char records[ROWS][COLS][MAX_CH] = { { { '\0'}}};//set each element
char item[MAX_CH] = { '\0'};//buffer for each item
//char yn[40];
int row = 0;
int col = 0;
int usedcol = 0;
int sortby[COLS] = { 0};
int ch = 0;
int each = 0;
int loop = 0;
int result = 0;
if ( argc < 2 || argc > COLS + 1) {
fprintf ( stderr, "syntax is\n%s column0 [column1]...[column%d] < inputfile\n", argv[0], COLS - 1);
exit(EXIT_FAILURE);
}
for ( each = 1; each <= COLS + 1; each++) {// +1 to get to extra element
sortby[each - 1] = -1;//extra element will be -1
if ( each < argc) {
if ( ( result = sscanf ( argv[each], "%d", &sortby[each - 1])) != 1 || sortby[each - 1] < 0 || sortby[each - 1] >= COLS) {
fprintf ( stderr, "syntax is\n%s column0 [column1]...[column%d] < inputfile\n", argv[0], COLS - 1);
fprintf ( stderr, "column%d must be 0 to %d\n", each - 1, COLS - 1);
exit(EXIT_FAILURE);
}
}
}
for ( each = 0; each < argc - 1; each++) {
for ( loop = 0; loop < argc - 1; loop++) {
if ( loop != each && sortby[each] == sortby[loop]) {
fprintf ( stderr, "found duplicate columns in args\n");
exit(EXIT_FAILURE);
}
}
}
//printf ( "\n");
if ( isatty ( fileno ( stdin))) {
printf ( "expected that a file would be redirected to this program\n");
printf ( "syntax is\n%s column0 [column1]...[column%d] < inputfile\n", argv[0], COLS - 1);
//printf ( "enter y to continue WITHOUT the redirected file?\n");
//if ( ( fgets ( yn, sizeof ( yn), stdin))) {
//if ( strcmp ( yn, "y\n") != 0) {
exit(EXIT_FAILURE);
//}
//}
}
row = 0;
col = 0;
each = 0;
while ( ( ch = getchar ( )) != EOF) {//read each character
if ( ch == '\r') {//skip carriage return
continue;
}
if ( ch == '\t') {
strcpy ( records[row][col], item);
each = 0;//back to first character
col++;//next column
if ( col >= COLS) {
col = 0;
row++;
if ( row >= ROWS) {
fprintf ( stderr, "too many rows\n");
break;
}
}
continue;
}
if ( ch == '\n') {
strcpy ( records[row][col], item);
col++;
if ( col > usedcol) {
usedcol = col;
}
col = 0;//back to first column
each = 0;//back to first character
row++;//next row
if ( row >= ROWS) {
fprintf ( stderr, "too many rows\n");
break;
}
continue;
}
item[each] = ch;
each++;//next character
item[each] = '\0';//terminate with '\0'
if ( each >= MAX_CH - 1) {
fprintf ( stderr, "too many characters in item\n");
each = 0;
col++;
if ( col >= COLS) {
col = 0;
row++;
if ( row >= ROWS) {
fprintf ( stderr, "too many rows\n");
break;
}
}
continue;
}
}
print_array ( records, row, usedcol, sortby, 0);
sort_array ( records, row, usedcol, sortby);
print_array ( records, row, usedcol, sortby, 1);
return 0;
}
void print_array(char str[][COLS][MAX_CH], int nrows, int ncols, int col[], int reorder) {
int i, j;
int order[COLS] = { 0};
for ( i = 0; i < COLS; i++) {
if ( reorder) {
order[i] = col[i];
}
else {
order[i] = i;
}
}
if ( reorder) {
for ( i = 0; i < COLS; i++) {
for ( j = 0; j < COLS; j++) {
if ( order[j] == i) {
break;
}
if ( order[j] == -1) {
order[j] = i;
break;
}
}
}
}
for (i = 0; i < nrows; i++) {
for (j = 0; j < ncols; j++) {
printf("%-12s ", str[i][order[j]]);
}
printf("\n");
}
printf("\n");
}
void sort_array(char str[][COLS][MAX_CH], int nrows, int ncols, int col[]) {
int i = 0, j = 0, swap = 0, each = 0;
char temp[MAX_CH] = { '\0'};
do {
swap = 0;
for ( i = 1; i < nrows - 1; i++) {//iterate through rows. i=1 skip first row
for ( each = 0; col[each] != -1; each++) {//col[] has last element of -1
if ( strcmp( str[i][col[each]], str[i + 1][col[each]]) < 0) {
break;
}
if ( strcmp( str[i][col[each]], str[i + 1][col[each]]) == 0) {
continue;
}
for ( j = 0; j < ncols; j++) {//iterate through cols and swap rows
strcpy ( temp, str[i][j]);
strcpy ( str[i][j], str[i + 1][j]);
strcpy ( str[i + 1][j], temp);
}
swap = 1;
break;
}
}
} while ( swap);//loop until no swaps
}
You can read by lines and then apply strtok() using '\t' as delimiter.
Reference for strtok() (it's from cplusplus.com, but strtok is in string.h, so it works also in c)
The posted code contains several problems:
unused stack variable records[][]
unused parameter: argc
unused parameter: argv
places all input data into first entries in the arrays: country[], sport[], gender[], medal[] I.E. all the other entries are not used
does not handle 'columns' that contain any white space
includes a header file those contents are not used: string.h
The following code cleanly compiles and performs the desired function:
#include <stdio.h>
#include <stdlib.h>
//#include <string.h>
#define ROWS 1000
//#define COLS 30
#define MAX_CH 49
struct record
{
char country[ MAX_CH+1 ];
char sport [ MAX_CH+1 ];
char gender [ MAX_CH+1 ];
char medal [ MAX_CH+1 ];
};
int main( void )
{
struct record records[ROWS];
for( size_t i=0; i< ROWS; i++)
{
if( scanf(" %" MAX_CH "[^\t] %" MAX_CH "[^\t] %" MAX_CH "[^\t] %" MAX_CH "[^\n]",
records[i].country,
records[i].sport,
records[i].gender,
records[i].medal) == 4)
{
printf("%s %s %s %s\n",
records[i].country,
records[i].sport,
records[i].gender,
records[i].medal);
}
else
{
break;
}
}
return 0;
} // end function: main
Related
I have a function that manipulates a char*** using malloc and memcpy this way
// Convert a buffer full line to separated variables
int parseBufferToVariables(char ***variableContainer, char *bufferToParse, int maxVarSize) {
int i = 0;
// Get number of rows of the string
int numberOfRows = 0;
for (i = 0; bufferToParse[i] != '\0'; i++) {
if (bufferToParse[i] == '\n')
++numberOfRows;
}
// Get number of columns of the string
int numberOfColumns = 1;
for (i = 0; bufferToParse[i] != '\n'; i++) {
if (bufferToParse[i] == '\t')
++numberOfColumns;
}
// Allocate separated variable array
size_t dim0 = numberOfColumns, dim1 = numberOfRows, dim2 = maxVarSize;
variableContainer = malloc(sizeof *variableContainer * dim0);
if (variableContainer) {
size_t i;
for (i = 0; i < dim0; i++) {
variableContainer[i] = malloc(sizeof *variableContainer[i] * dim1);
if (variableContainer[i]) {
size_t j;
for (j = 0; j < dim1; j++) {
variableContainer[i][j] = malloc(sizeof *variableContainer[i][j] * dim2);
}
}
}
}
// Start parsing string to 3D array
int init = 0;
int numberOfVars = 0;
int numberOfLines = 0;
int sizeOfVar = 0;
int position = 0;
char emptyArray[MAXVARSIZE] = {0};
// Loop trought all lines
i = 0;
while (numberOfLines < numberOfRows) {
// Every delimiter
if (bufferToParse[i] == '\t' || bufferToParse[i] == '\n') {
// Size of the new sring
sizeOfVar = i - init;
// Set last \0 character in order to recognize as a proper string
memcpy(&variableContainer[numberOfVars][numberOfLines], emptyArray, maxVarSize);
// Copy the string to array
memcpy(&variableContainer[numberOfVars][numberOfLines], &bufferToParse[position], sizeOfVar);
// Handle pointers poisition
init = i + 1;
position += sizeOfVar + 1;
// Handle when end of line is reached
if (bufferToParse[i] == '\n') {
numberOfVars = 0;
numberOfLines++;
}
}
i++;
}
return numberOfRows;
}
And Im trying to call it in different ways:
char*** container= {0};
parseBufferToVariables (&container, inputString, MAXVARSIZE);
char*** container= {0};
parseBufferToVariables (container, inputString, MAXVARSIZE);
Even I try calling a char**** in the function:
int parseBufferToVariables(char**** variableContainer, char* bufferToParse, int maxVarSize)
But I always have a seg-fault calling the char*** outside the parseBufferToVariables function.
Any ideas?
OP is shooting for a 4 * parameter, yet other approaches are better.
The high degree of *s mask a key failing is that code needs to convey the column (# of tabs) width somehow.
Further, I see no certain null character termination in forming the _strings_as
the 2nd memcpy() is unbounded in size - may even overwrite allocation boundaries.
The idea below is that each level of allocation ends with a null.
csv = parse_file_string(const char *file_string);
Upon return, when csv[line] == NULL, there are no more lines
When csv[line][tab] == NULL, there are no more strings.
This approach also allows for a different number of strings per line.
Adjusted algorithm, pseudo C code
// return NULL on error
char ***parse_file_string(const char *file_string) {
number_lines = find_line_count(file_string);
char ***csv = calloc(number_lines + 1, sizeof *csv);
if (csv == NULL) return NULL;
for (line=0; line < number_lines; line++) {
tab_count = find_tab_count(file_string);
csv[line] = calloc(tab_count + 2, sizeof *(csv[line]));
// add NULL check
for (tab=0; tab < tab_count; tab++) {
char *end = strchr(file_string, '\t');
csv[line][tab] = malloc_string(file_string, end);
// add NULL check
file_string = end + 1;
}
char *end = strchr(file_string, '\n');
csv[line][tab++] = malloc_str(file_string, end);
// add NULL check
file_string = end + 1;
csv[line][tab] = NULL;
}
csv[line] = NULL;
return csv;
}
Usage
char ***container = parse_file_string(file_string);
for (line=0; container[line]; line++)
for (tab=0; container[line][tab]; tab++)
puts(container[line][tab]);
//free
for (line=0; container[line]; line++)
for (tab=0; container[line][tab]; tab++)
free(container[line][tab]);
free(container[line]);
free (container)
A pointer to a variable length array could be used if supported.
First get the dimensions of the contents of the buffer. This assumes that each line will have the same number of tabs.
Declare the pointer and allocate the memory.
Then parse the buffer into the allocated memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getdimension ( char *buffer, int *rows, int *cols, int *size) {
int maxsize = 0;
*rows = 0;
*cols = 0;
*size = 0;
while ( *buffer) {//not the terminating zero
if ( '\n' == *buffer) {
if ( ! *rows) {//no rows counted yet
++*cols;//add a column
}
++*rows;
if ( maxsize > *size) {
*size = maxsize;
}
maxsize = 0;
}
if ( '\t' == *buffer) {
if ( ! *rows) {//no rows counted yet
++*cols;
}
if ( maxsize > *size) {
*size = maxsize;
}
maxsize = 0;
}
++maxsize;
++buffer;
}
if ( '\n' != *(buffer - 1)) {//last character is not a newline
++*rows;
if ( maxsize > *size) {
*size = maxsize;
}
}
}
void createptr ( int rows, int columns, int size, char (**ptr)[columns][size]) {
if ( NULL == ( *ptr = malloc ( sizeof **ptr * rows))) {
fprintf ( stderr, "malloc problem\n");
exit ( EXIT_FAILURE);
}
for ( int line = 0; line < rows; ++line) {
for ( int tab = 0; tab < columns; ++tab) {
(*ptr)[line][tab][0] = 0;
}
}
}
void parsebuffer ( char *buffer, int rows, int columns, int size, char (*ptr)[columns][size]) {
int eachrow = 0;
int eachcol = 0;
int eachsize = 0;
while ( *buffer) {
if ( '\n' == *buffer) {
++eachrow;
eachcol = 0;
eachsize = 0;
}
else if ( '\t' == *buffer) {
++eachcol;
eachsize = 0;
}
else {
ptr[eachrow][eachcol][eachsize] = *buffer;
++eachsize;
ptr[eachrow][eachcol][eachsize] = 0;
}
++buffer;
}
}
int main ( void) {
char line[] = "12\t34\t56\t78\t!##\n"
"abc\tdef\tghi\tjkl\t$%^\n"
"mno\tpqr\tstu\tvwx\tyz\n"
"ABC\tDEF\tGHI\tJKL\tMNOPQ\n";
int rows = 0;
int columns = 0;
int size = 0;
getdimension ( line, &rows, &columns, &size);
printf ( "rows %d cols %d size %d\n", rows, columns, size);
char (*ptr)[columns][size] = NULL;//pointer to variable length array
createptr ( rows, columns, size, &ptr);
parsebuffer ( line, rows, columns, size, ptr);
for ( int row = 0; row < rows; ++row) {
for ( int col = 0; col < columns; ++col) {
printf ( "ptr[%d][%d] %s\n", row, col, ptr[row][col]);
}
}
free ( ptr);
return 0;
}
I'm stuck with sorting letters in a string. It must be sorted in alphabetical order using double pointers.
#define SIZE 21 //defined index of the array
int _tmain(int argc, _TCHAR* argv[])
{
// an array with 21 strings
char * string[SIZE] = { "dfghgfd", "rtyukljgfds", "sdsf", "fdgdfhg", "fgfhgjghj", "nmjlkjlk", "qwasazx",
"zxdfd", "opiljkg", "vcxdfgfd", "fgfhgfhgh", "bvvh", "bb", "dfsdretr",
"reuio", "cvbmhg", "fgfdyrtyty", "fgdgdfgdfgdf", "g", "fgdfg", "ghghgfhv" };
-----------------------Access to each string in array ------------------------
int Anz, i; //Anz - 21 strings
//declared new array
char** new_string;
new_string = (char**)malloc(sizeof(string));
Anz = sizeof(string) / sizeof(char*);
for (i = 0; i < Anz; i++)
{
new_string[i] = (char*)malloc(strlen(string[i]) + 1);
strcpy(new_string[i], string[i]);
}
----------------------- sorting letters--------------------------------------
char* temp;
int k, j;
for (k = 0; k<Anz - 1; k++)
{
for (j = k + 1; j<Anz; j++)
{
if (new_string[k] > new_string[j])
{
temp = new_string[k];
new_string[k] = new_string[j];
new_string[j] = temp;
}
}
}
return 0;
}
Not sure why you need the "a" array, since you can swap the characters using the new string array. Also, using a char * to hold the length of values is sort weird but I guess it works since the string lengths are pretty short.
Not sure if you wanted to sort the letters or the words. A commented section sorts the words.
Check the return of malloc as it can fail.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 21 //defined index of the array
int main(int argc, char** argv)
{
// an array with 21 strings
char * string[SIZE] = { "dfghgfd", "rtyukljgfds", "sdsf", "fdgdfhg", "fgfhgjghj", "nmjlkjlk", "qwasazx",
"zxdfd", "opiljkg", "vcxdfgfd", "fgfhgfhgh", "bvvh", "bb", "dfsdretr",
"reuio", "cvbmhg", "fgfdyrtyty", "fgdgdfgdfgdf", "g", "fgdfg", "ghghgfhv" };
int Anz, i; //Anz - 21 strings
int width = 0, len = 0;
//declared new array
char** new_string;
Anz = sizeof(string) / sizeof(*string);
if ( NULL == ( new_string = malloc ( Anz * sizeof( *new_string)))) {
fprintf ( stderr, "malloc failed\n");
return 0;
}
for (i = 0; i < Anz; i++)
{
len = strlen ( string[i]) + 1;
if ( len > width) {
width = len;//used later when printing
}
if ( NULL == ( new_string [i] = malloc ( width))) {
fprintf ( stderr, "[i] malloc failed\n");
//free memory allocated
while ( i) {
i--;
free ( new_string[i]);
}
free ( new_string);
return 0;
}
strcpy(new_string[i], string[i]);
}
/*
//sort words
int word = 0;
while ( word < Anz - 1) {
int end = word;
int temp = end + 1;
while ( end >= 0 && 0 > strcmp ( new_string[temp], new_string[end])) {
char *hold = new_string[temp];
new_string[temp] = new_string[end];
new_string[end] = hold;
end--;
temp--;
}
word++;
}
word = 0;
while ( word < Anz) {
printf ( "Anz[%2d] is %s\n", word, new_string[word]);
word++;
}
*/
//sort letters in word
char swap;
int sorted;
int prior;
int each;
int start;
word = 0;
while ( word < Anz)
{
start = 0;//new_string[Anz][0]
sorted = start;
prior = start;
each = start + 1;//new_string[Anz][1]
printf ( "Anz[%2d] is %-*s", word, width, new_string[word]);
while ( '\0' != new_string[word][each]) {
while ( prior >= 0 && new_string[word][each] < new_string[word][prior]) {
swap = new_string[word][each];
new_string[word][each] = new_string[word][prior];
new_string[word][prior] = swap;
each--;//move toward start of string
prior--;
}
sorted++;//move toward end of string
prior = sorted;
each = prior + 1;
}
printf ( " sorted %s\n", new_string[word]);
word++;
}
//release allocated memory
word = 0;
while ( word < Anz) {
free ( new_string[word]);
word++;
}
free ( new_string);
return 0;
}
I know that I can scanf certain amount of numbers with scanf for example for 3 numbers
scanf("%d %d %d",array[0],array[1],array[2]);
but how can I scan it if I didn't know how many numbers (integer, not float) I would input into an array before enter (NOT EOF)? for example
input : 12 43 23(enter) --> array[0]=12, array[1]=43, array[2]=23
input : 10 20 30 40 50(enter) --> array[0]=10, array[1]=20, array[2]=30, array[3]=40, array[4]= 50
etc..
It's about how to input the numbers into an integer array.
And if it's possible, I want to save it into an 2 dimensions array, for example
input : 12 43 23(enter) --> array[0][0]=12, array[0][1]=43, array[0][2]=23
input : 10 20 30 40 50(enter) --> array[1][0]=10, array[1][1]=20, array[1][2]=30, array[1][3]=40, array[1][4]= 50
Here is come code showing how to scan the integers into a 2D array:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INITSIZE 5
#define BUFFSIZE 1000
void print_and_free(int **array, int rowsize, int colsize);
void check_ptr(void *ptr, const char *msg);
int
main(void) {
int **array;
size_t rowsize = INITSIZE, colsize = INITSIZE;
int row = 0, col, numdigits;
char buffer[BUFFSIZE];
char *number;
array = malloc(rowsize * sizeof(*array));
check_ptr(array, "Allocation");
printf("Enter digits(Enter blank line to end):\n");
while (fgets(buffer, BUFFSIZE, stdin) != NULL && strlen(buffer) != 1) {
col = 0;
numdigits = 0;
if (rowsize == row) {
rowsize *= 2;
array = realloc(array, rowsize * sizeof(*array));
check_ptr(array, "Reallocation");
}
array[row] = malloc(colsize *sizeof(int));
check_ptr(array[row], "Allocation");
number = strtok(buffer, " ");
while (number != NULL) {
numdigits++;
if (colsize == numdigits) {
colsize *= 2;
array[row] = realloc(array[row], colsize * sizeof(int));
check_ptr(array[row], "Reallocation");
}
array[row][col] = atoi(number);
col++;
number = strtok(NULL, " ");
}
row++;
}
print_and_free(array, row, col);
return 0;
}
void
print_and_free(int **array, int rowsize, int colsize) {
int row, col;
printf("Your numbers:\n");
for (row = 0; row < rowsize; row++) {
for (col = 0; col < colsize; col++) {
printf("array[%d][%d] = %d", row, col, array[row][col]);
if (col != colsize - 1) {
printf(", ");
}
}
free(array[row]);
array[row] = NULL;
printf("\n");
}
free(array);
}
void
check_ptr(void *ptr, const char *msg) {
if (!ptr) {
printf("Unexpected null pointer: %s\n", msg);
exit(EXIT_FAILURE);
}
}
Here's how you can store things in a (dynamically allocated) array. This does assume that the line length is limited to 1000 chars though. (Code adapted from How do I use scanf() to take an arbitrary amount of integers?)
#include <stdio.h>
#include <stdlib.h>
int main() {
int val_size = 2;
int* vals = (int*)malloc(val_size * sizeof(int)); // initial array size
char buffer[1000]; // for reading in the line
int pos, bytes_read, num;
int num_read = 0;
if (fgets(buffer, sizeof(buffer), stdin) != 0) {
for (pos = 0; sscanf(buffer+pos, "%d%n", &num, &bytes_read) != EOF; pos += bytes_read) {
// resize the array if needed
if (num_read >= val_size) {
val_size *= 2;
vals = (int*)realloc(vals, val_size * sizeof(int));
}
// store the value in the array
vals[num_read] = num;
num_read++;
}
}
// print the values to prove it works
for (int i = 0; i < num_read; i++) {
printf("%d ", vals[i]);
}
printf("\n");
free(vals); // important after you're done with it
}
You can wrap a while around the if to get multiple lines.
You may use a while loop and check for the return value of scanf. For example:
int num = 0;
int idx = 0;
int arr[100] = { 0 };
while( scanf( "%d", &num ) == 1 )
{
arr[idx++] = num;
if( idx == 99 ) // protect from array overflow
{
break;
}
}
for( int i = 0; i < idx; i++ )
{
printf( "%d\n", arr[i] );
}
I have problem with extracting numbers from string.
Problem is I can not use strtol or isdigit functions as teacher requested so.
I am supposed to save numbers in new array.
For example, string input:
11-some12meh13text-14
.
So new array would be:
11,12,13,14
(NOT -14)
I came to idea to do following:
char str1[150];
int array[20];
int temporary, i=0, j=0; //i - for string, j - for array
for(i=0;i<=strlen(str1);i++) {
if(i==0) { //not needed to check if char before was number
if((str1[i]>=0) && (str1[i]<=9))temporary=str1[i];
if((str1[i+1]<=0) && (str1[i+1]>=9)) {//if next char is NOT number
array[j]=temporary;
j++;
}
}
else if(i!=0) { //needs to be checked if char before was number
if((str1[i]>=0) && (str1[i]<=9)) {
if((str1[i-1]>=0) && (str1[i-1]<=9))temporary=temporary*10+str1[i];
else temporary=str1[i];
if((str1[i+1]<=0) && (str1[i+1]>=9)) {//if next char is NOT number
array[j]=temporary;
j++;
}
}
}
}
I tried it on my PC, but program crashes and I have no idea or ability to find what I did wrong.
Please help!
Thank you!
The integral values of characters '0'...'9' are not 0...9.
Hence, change every occurrence of str1[k] to str1[k]-'0'.
If using sscanf() is allowed, this will parse the string for integers. The %n specifier will report the number of characters processed by the scan. This lets you move through the string.
When the scan for an integer fails ( != 1), the scanset "%*[^0-9\n]%n" scans and discards characters that are not a digit or newline. The %n captures the number of characters processed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( ) {
char str1[150] = {"0+1-=2!3*4-5/6#7&8|9^10"};
int array[20] = {0};
int offset = 0;
int each = 0;
int loop = 0;
int used = 0;
int length = 0;
length = strlen ( str1);
do {
sscanf ( str1 + offset, "%*[^0-9\n]%n", &used);
offset += used;
if ( ( sscanf ( str1 + offset, "%d%n", &array[each], &used)) == 1) {
offset += used;
each++;
if ( each >= 20) {
break;
}
}
} while ( offset < length);
for ( loop = 0; loop < each; loop++) {
printf ( "%d\n", array[loop]);
}
return 0;
}
Here is a version of your code that seems to work
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( ) {
char str1[150] = {"-0+1-=2!3*4-text-5/6#7&8|9^10 11end"};
int array[20] = {0};
int each = 0;
int loop = 0;
int saved = 1;
int length = 0;
int temporary = 0, i=0;
length = strlen ( str1);
for ( i = 0; i < length; i++) {
if ( ( str1[i] >= '0') && ( str1[i] <= '9')) {//found a digit
temporary = ( temporary * 10) + ( str1[i] - '0');
saved = 0;//flag not saved. temporary value may change
}
else {//found NOT a digit
if ( i > 0 && !saved) {//not at first character and not saved
array[each] = temporary;//save integer
each++;
saved = 1;//flag saved
temporary = 0;//reset
if ( each >= 20) {
break;
}
}
}
}
if ( !saved && each < 19) {//end of string is an integer. save it
array[each] = temporary;
each++;
}
for ( loop = 0; loop < each; loop++) {
printf ( "%d\n", array[loop]);
}
return 0;
}
I am new to programming in C, and I'm working on a simple program to take the user input (a basic phone number, ie: (678)-653.7539), and will output it in standard format).
The approach I took was first taking out all periods, hyphens, and parenthesis.
Currently the program prints out just numbers, however the format I want is:
(xxx) xxx-xxxx
I'm thinking creating a method with an array, and then iterating through (similar to stack?) having it input "(" before i[0] and again after i[2], and so on.
Is this the right approach?
#include <stdio.h>
void removeHyphen( char s[], char x );
void removeLeftParen( char s[], char f );
void removeRightParen( char s[], char g );
void removePeriod( char s[], char h );
int main()
{
char s[50];
printf("Enter your phone number:\n");
scanf("%s", s);
printf( "Your phone number: %.13s\n", s );
removeHyphen( s, '-' );
removeLeftParen(s, '(');
removeRightParen(s, ')');
removePeriod(s, '.');
printf( "Formatted phone number: %.10s\n", s );
getchar();
return 0;
}
void removeHyphen(char s[], char x)
{
int i, j;
for (i = 0 ; s[i] != 0 ; ++i)
{
while(s[i]==x)
{
j=i;
while(s[j]!=0)
{
s[j]=s[j+1];
++j;
}
}
}
}
void removeLeftParen(char s[], char f)
{
int i, j;
for (i = 0 ; s[i] != 0 ; ++i)
{
while(s[i]==f)
{
j=i;
while(s[j]!=0)
{
s[j]=s[j+1];
++j;
}
}
}
}
void removeRightParen(char s[], char g)
{
int i, j;
for (i = 0 ; s[i] != 0 ; ++i)
{
while(s[i]==g)
{
j=i;
while(s[j]!=0)
{
s[j]=s[j+1];
++j;
}
}
}
}
void removePeriod(char s[], char h)
{
int i, j;
for (i = 0 ; s[i] != 0 ; ++i)
{
while(s[i]==h)
{
j=i;
while(s[j]!=0)
{
s[j]=s[j+1];
++j;
}
}
}
}
You know exactly what your end product should look like. It'll be char result[15]. So a simple brute force algorithm would look like:
//set the known characters in the output string
result[ 0 ] = '(';
result[ 4 ] = ')';
result[ 5 ] = ' ';
result[ 9 ] = '-';
result[ 14 ] = '/0'; //null terminator
int index = 0;
//pseudocode
foreach( character in input )
if character is a number
if index == 0, 4, 5, 9
++index;
if index == 14 //we're out of room
print result;
exit;
result[ index++ ] = character;
else
ignore character
Where "character is a number" would probably be the only function you'd need to write.
You may not need all the remove logic. You may just iterate over the input and copy the numeric characters.
Pseudo-code idea:
char output[50]; // better: char output[sizeof input];
// This is essentially processed/normalized input.
// In fact, since we know that it is a 10-digit
// phone number we can just do: char output[10];
// If you ever need to store the phone number for
// long term, the last option may be the best option.
const int n = actual length of input, e.g. strlen()
int j = 0;
for (int i = 0; i < n; ++i) {
if (isdigit((unsigned char) input[i]) {
output[j++] = input[i];
}
}
// Validate 'output', for e.g. check that it has 10 characters
// Print output in desired format
See manual page for isdigit().
A different program structure employing the same idea is the following. While accepting input, scan them as characters and ignore the non-digit characters.
I suggest the use of strtok.
The following is an example
#include <stdio.h>
#include <string.h>
int main(void){
char s[50], f[50];
char *part[3] = { NULL };
char *p;
int i;
printf("Enter your phone number:\n");
scanf("%49s", s);
printf( "Your phone number: %s\n", s );
p = strtok(s, "-().");
for(i=0; p!=NULL && i<3; ++i){
part[i] = p;//Better to add one of the check is made up of numbers.
p = strtok(NULL, "-().");
}
if(i==3){
sprintf(f, "(%s) %s-%s", part[0], part[1], part[2]);
printf( "Formatted phone number: %s\n", f );
} else {
printf("invalid format\n");
}
getchar();
return 0;
}
After you have removed all the unwanted characters you can do this
void printFormatted(char *s)
{
int i;
if (s == NULL)
return;
fputc('(', stdout);
for (i = 0 ; ((i < 3) && (s[i] != '\0')) ; ++i)
fputc(s[i], stdout);
fputc(')', stdout);
fputc(' ', stdout);
if (s[i] == '\0')
return;
for ( ; ((i < 6) && (s[i] != '\0')) ; ++i)
fputc(s[i], stdout);
fputc('-', stdout);
if (s[i] == '\0')
return;
for ( ; s[i] != '\0' ; ++i)
fputc(s[i], stdout);
fputc('\n', stdout);
}
Although you don't really need to remove anything if you are just interested in the output of the program, you could use this
#include <stdio.h>
#include <ctype.h>
void printFormatted(char *phone);
int main()
{
char phone[50];
printf("Enter your phone number: ");
if (scanf("%49s%*c", phone) == 1)
{
printf( "Your input : %s\n", phone);
printf("Formatted phone number : ");
printFormatted(phone);
printf("\n");
}
return 0;
}
int putdigit(char digit)
{
/* Print a charater if it's a digit (0-9) */
if (isdigit((int)digit) == 0)
return 0;
fputc(digit, stdout);
return 1;
}
void printFormatted(char *phone)
{
int i;
int j;
/* Always be safe */
if (phone == NULL)
return;
/* Output the `(' */
fputc('(', stdout);
/* Output 3 digits */
for (i = 0, j = 0 ; ((j < 3) && (phone[i] != '\0')) ; ++i)
j += putdigit(phone[i]);
/* Output the `)' and a space */
fputc(')', stdout);
fputc(' ', stdout);
/* Check if there are more characters */
if (phone[i] == '\0')
return;
/* Output 3 digits */
for (j = 0 ; ((j < 3) && (phone[i] != '\0')) ; ++i)
j += putdigit(phone[i]);
/* Output the hypen */
fputc('-', stdout);
/* Check if there are more characters */
if (phone[i] == '\0')
return;
/* Output the rest of the characters */
for ( ; phone[i] != '\0' ; ++i)
putdigit(phone[i]);
fputc('\n', stdout);
}
Another approach. Build the string per an interpreted format.
#include <ctype.h>
// 0: success, 1 fail
int FormatPhoneNumber(const char *format, char *dest, const char *src) {
int i;
for (i = 0; format[i]; i++) {
if (format[i] == 'x') {
while (!isdigit((unsigned char) *src)) {
if (*src++ == '\0') {
dest[i] = '\0';
return 1; // fail, missing digit
}
}
dest[i] = *src++;
} else {
dest[i] = format[i];
}
}
dest[i] = '\0';
while (*src && !isdigit((unsigned char) *src)) src++;
return *src ? 1 : 0;
}
#include <stdio.h>
int main(void) {
const char format[] = "(xxx) xxx-xxxx";
char buf[sizeof format];
int result = FormatPhoneNumber(format, buf, " (678)-653.7539),");
printf("%d '%s'\n", result, buf);
result = FormatPhoneNumber(format, buf, "Jenny: 111-867-5309");
printf("%d '%s'\n", result, buf);
return 0;
}
0 '(678) 653-7539'
0 '(111) 867-5309'