Question:
C question: Checking 2D array of chars?
1970-01-01 00:00:00 UTC
C question: Checking 2D array of chars?
Three answers:
husoski
2011-11-19 10:19:53 UTC
That sounds and looks like one-dimensional array of (up to 70000) strings that could hold 0-50 characters each. If so, try thinking of it that way instead of as a "2D array". An expression using your array with a single subscript, like stringArray[i], has type char[51] and refers to one of those strings.



Meanwhile, to get formatted elements out of a character string, one of the most powerful tools in the Standard C Library is sscanf(). It's not as powerful as regular expressions (Perl-compatible or not) but it does not require a 3rd-party library, either. Your example of "v 123 45 6789", where I'm assuming spaces as a separators for the numbers, could be parsed with:



#include /* need this for strncmp() */

#include /* and this for sscanf() */

...

char sbuf[51]; /* Input string. Shorter to type than stringArray[i] for this example */

int num1, num2, num3; /* three numbers from a "v _ _" line */

int n; /* something to hold return value from sscanf() */

char junk; /* someplace to store an invalid extra character */

...

if (strncmp(sbuf, "v ", 3) == 0) /* If line starts with 'v', ' ', ' ' */

{

... n = sscanf("%d %d %d %c", sbuf+3, &num1, &num2, &num3, &junk);

... if (n == 3)

... ... store_vRecord(num1, num2, num3);

... else { bad input line }

}



The first bit to note in particular is the strncmp() call. Make sure that "v " has TWO spaces after the v. That will compare for exactly 'v', ' ', ' ' in the first three positions of sbuf, returning 0 on equality and nonzero otherwise. (The sign of a nonzero result is significant if you're sorting or merging, but that's not used here.) Note that the 0 terminator in the "v " string is NOT used since the compare stops after three characters.



The sscanf() call looks for three integer (%d) tokens, separated by (any number of) whitespace characters, followed by 0 or more trailing whitespace characters, plus one additional non-whitespace character value (%c), starting with the 4th position in sbuf (sbuf+3). The values are stored, in the order found, in num1, num2, num3, junk.



The return value from sscanf() tells how many values were stored. With this format string, a return value of 3 means that exactly three decimal numbers were found, with no trailing garbage. If the return was less than 3, then either fewer than 3 numbers were found, or an invalid character was seen in one of the first two, or starting the third number. If 4 is returned, then three numbers were found and stored, but there was at least one extra non-whitespace and non-digit character at the end of the line.



You don't have to treat n==4 as an error, but you can if you like.



You could hack the first three characters into the sscanf() format too, by using "%c%c%c" at the front of the format for three separate char variables, or %3c to read them into a (NOT 0-terminated) char[3] array. I think it's easier to use strncmp() to compare fixed-column data.



I'm not sure what you mean by "sub array", but this should get you going.



PS: If you're using floating point instead of int data, take note that scanf() formats are different from printf(). For scanf(), %f means float, not double. If your variables are doubles, use %lf in your sscanf format string.
2011-11-19 02:28:49 UTC
Use regular expressions.



What you are doing would be better done in Perl or another dynamic language with built in regex support, but you can do it in C with the PCRE (Perl Compatible Regular Expression) library.



It's probably a bad idea to read the entire file in at once into a static structure. It doesn't scale, it's wasteful, and it's begging for problems (EG buffer overflows). Process your input line by line and dynamically allocate storage as it's needed.



in Perl:



#!/usr/bin/perl

use strict;

use warnings;



my @answers; # array of answers

while (my $line = <>) { # read from STDIN, breaking on newlines

my ($number) = $line =~ /v (\d{3})/; # match and capture

if ( defined($number) ) {

push @answers, $number; # append number to array

}

}

# do what you want with @answers

print join("\n", @answers), "\n";



The key bit is the regular expression /v (\d{3})/

C implementation is left as an exercise for the reader. Why write 100 lines of C when 12 lines of Perl will get the job done?
Jim
2011-11-19 01:11:48 UTC
so... how are you going to separate the numbers in the string? otherwise, they are just jammed together, and they become one big number, right?

you need a string format specification and you need to write a lexer like you are going to read it character by character from left to right trying to figure out where the numbers begin and end.



this means you are going to have to keep character position variables that point to places where a number starts and one where a number ends, and keep a variable that holds the length of the string at the beginning of the loop so you are not constantly calling strlen() - this is hand optimization.



I wrote a lexer for numbers as a c++ library a while back that reads C strings and converts them into uint64_t or int64_t, standard integers in

#include

using namespace std;



atoi64_ and atou64_ both skip leading and trailing garbage. it also accepts many number formats, and accepts SI and IEC units suffixes.


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...