scanf() - getting field count and checking for EOF - c

I'm trying to parse and convert a csv and thought I'd try my hand at c since I'm currently learning the language.
int main()
{
char * s1, * s2;
int field_count = 0;
while ((field_count = scanf("%20[^;];%s", s1, s2)) != EOF)
{
printf("%d\n", field_count));
if (field_count != 2)
continue;
}
return 0;
}
I don't get why field_count is always 0 no matter how many fields there are in each line, and the loop never ends either.
I tried changing the while clause to:
while ((field_count = scanf("%s", s1)) != EOF)
but it made no difference.
I've tried googling, but examples retaining the return value AND checking for EOF were hard to find.

This is an example of code that should work.
It allocates a storage buffer for s1 and s2.
This code expects that the fields are at most 99 characters long.
int main(int argc, char * argv[])
{
char s1[100], s2[100];
int field_count = 0;
while ((field_count = scanf("%99[^;];%99[^\n]", s1, s2)) >= 0)
{
printf("%d '%s' '%s'\n", field_count, s1, s2);
}
return 0;
}
Scanf is a bit limited to parse an input string. You might get unexpected result when you give it an empty string.

Related

Put characters from a char array in a string till a specific character is found

I'd like a reliable method to read the characters from a character array and put them in a string. This will happen till a \r is found. I can iterate through the array but have no good way to put that in a string. I am afraid to use malloc since, at times, puts garbage value in a string.
Here payload is the HTTP data from a TCP packet. \r\n\r\n indicates the end of the payload.
My code so far to iterate through the character array:
void print_payload(const unsigned char *payload, int len) {
int i;
const unsigned char *ch = payload;
for (i = 0; i < len; i++) {
if (strncmp((char*) ch, "\r\n\r\n", 4) == 0) {
// Indicates end of payload data.
break;
} else if (strncmp((char*) ch, "\r\n", 2) == 0) {
//Indicates EOL
printf("\r\n");
ch++;
i++;
} else if(strncmp((char*) ch, "Host:", 5) == 0){
printf("Host: ");
const unsigned char *del = ch + 6;
int i = 0;
while (del[i] != 13 ){
/*
*13 is decimal value for '\r'.
* The characters below are to be inserted
* in a string. Not sure how though.
*/
printf("%c",del[i]);
i++;
}
} else if(strncmp((char*) ch, "User-Agent: ", 11) == 0){
/*
* It has to implemented here as well.
* And in every case where my string matches.
*/
printf("UserAgent: ");
const unsigned char* del = ch + 11;
int i = 0;
while(del[i] != 13){
printf("%c")
}
}
ch++;
}
printf("\r\n\r\n");
printf("\n");
return;
}
Can somebody help me achieve this? I know this is basic but I'm still learning C Programming and am not sure how to do this. Thank in advance.
You have a few options. First, if you can limit the size of the string, and do not need it outside of the function, then a char array would work:
#define STRING_MAX_LEN 999//chux mentions this is better then just putting "1000" in the array[] - 1000 needs to make sense in terms of the program, or something you wish to enforce (and checked!)
char newString[STRING_MAX_LEN+1] = {0};//Initialize to NULL value.
There is no reason to fear malloc though - just remember to work safely and free, and you should be fine:
char *newString = malloc(sizeof(char)*(len+1)); //Better limit on needed space - +1 for a final '\0'.
if (!newString) //Oh no! hard fail.
//do Something
}
memset(newString,0,sizeof(char)*(len+1)); //No garbage in my new string anymore!
...
...
free(newString);
//Finish up with program
You will not even have to append a '\0' - you are already sure the buffer is full of them, so you a valid C string. Note sizeof(char) may be redundant but I like to keep it anyway, in case one day it will not equal 1.
Note if you have to return the new string for some reason you must use a dynamically allocated array, using malloc. Finally, if you only need to check/hold one sub-string at a time, then re-using the same string is preferable.
void print_payload(const unsigned char *payload, int len)
{
int i;
char c;
char *p;
p = (char*)payload;
for(i=0;i<len;i++) {
if(!strncmp(&p[i],"\r\n\r\n",4)) {
c = p[i+4];
p[i+4] = 0;
break;
}
}
if(i==len) {
return;
}
printf("%s\n",p);
p[i+4] = c;
}

Storing values of file into array leads to weird behaviour

Let's say I've got the file
5f2
3f6
2f1
And the code:(The printf should print the second numbers (i.e 2,6, and 1) but it doesn't
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main (int argc, char * argv[])
{
FILE *ptr;
char str[100];
char * token;
int a, b, i;
int arr[4];
if(argc > 1)
{
ptr = fopen(argv[1],"r");
if(ptr == NULL)
{
exit(1);
}
}
else
{
exit(1);
}
//And I'm looking to parse the numbers between the "f" so..
while(fgets(str,100,ptr) != NULL)
{
token = strstr(str,"f");
if(token != NULL)
{
a = atol(str); // first number
b = atol(token+1); // second number
arr[i] = b; // store each b value (3 of em) into this array
}
i++;
printf("Values are %d\n",arr[i]); //should print 2,6 and 1
}
}
I've tried to move the printf outside the loop, but that seems to print an even weirder result, I've seen posts about storing integers from a file into an array before, however since this involves using strstr, I'm not exactly sure the procedure is the same.
int i,j=0;
while(fgets(str,sizeof(str),file) != NULL)
{
size_t n = strlen(str);
if(n>0 && str[n-1] == '\n')
str[n-1] = '\0';
i = str[strlen(str)-1] - '0'; /* Convert the character to int */
printf("%d\n",i);// Or save it to your int array arr[j++] = i;
}
Just move to the last character as shown and print it out as integer.
PS: fgets() comes with a newline character you need to suppress it as shown
You are never initializing i, then you are reading into arr[i] (which just happens to not crash right there), then increment i (to "undefined value + 1"), then print arr[i] -- i.e., you are writing to and reading from uninitialized memory.
Besides, your FILE * is ptr, not file. And you should get into the habit of using strtol() instead of atol(), because the former allows you to properly check for success (and recover from error).

Idenfifying a 10 digit number in middle of a string

I can have strings containing random 10 digit numbers e.g.
"abcgfg1234567890gfggf" or
"fgfghgh3215556890ddf" etc
basically any combination of 10 digits plus chars together in a string, so I need check the string to determine if a 10 digit number is present. I use strspn but it returns 0
char str_in[] = "abcgfg1234567890gfggf";
char cset[] = "1234567890";
int result;
result = strspn(str_in, cset); // returns 0 need it to return 10
The fact that the following code returns 0 instead of 10 highlights the problem. I asked this previously but most replies were for checking against a known 10 digit number. In my case the number will be random. Any better way than strspn?
It returns 0 because there are no digits at the start of the string.
The strspn() function calculates the length (in bytes) of the
initial segment of s which consists entirely of bytes in accept.
You need to skip non-digits - strcspn - and then call strspn on the string + that offset. You could try:
/* Count chars to skip. */
skip = strcspn(str_in, cset);
/* Measure all-digit portion. */
length = strspn(str_in + skip, cset)
EDIT
I should mention this must be done in a loop. For example if your string is "abcd123abcd1234567890" the first strspn will only match 3 characters and you need to look further.
Just use sscanf():
unsigned long long value;
const char *str_in = "abcgfg1234567890gfggf";
if(sscanf(str_in, "%*[^0-9]%uL", &value) == 1)
{
if(value >= 1000000000ull) /* Check that it's 10 digits. */
{
/* do magic here */
}
}
The above assumes that unsigned long long is large enough to hold a 10-digit decimal numbers, in practice this means it assumes that's a 64-bit type.
The %*[^0-9] conversion specifier tells sscanf() to ignore a bunch of initial characters that are not (decimal) digits, then convert an unsigned long long (%uL) directly after that. The trailing characters are ignored.
How about using a regex?
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
int
main(int argc, char **argv)
{
char str_in[] = "abcgfg1234567890gfggf";
int result = 0;
const char *pattern = "[0-9]{10}";
regex_t re;
char msg[256];
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
perror("regcomp");
return(EXIT_FAILURE);
}
result = regexec(&re, str_in, (size_t)0, NULL, 0);
regfree(&re);
if (!result) {
printf("Regex got a match.\n");
} else if (result == REG_NOMATCH) {
printf("Regex got no match.\n");
} else {
regerror(result, &re, msg, sizeof(msg));
fprintf(stderr, "Regex match failed: %s\n", msg);
return(EXIT_FAILURE);
}
return(EXIT_SUCCESS);
}
strspn seems handy for this, but you would have to include it in a loop and search several times. Given the specific requirements, the easiest way is probably to make your own custom function.
int find_digits (const char* str, int n);
/* Searches [str] for a sequence of [n] adjacent digits.
Returns the index of the first valid substring containing such a sequence,
otherwise returns -1.
*/
#include <ctype.h>
int find_digits (const char* str, int n)
{
int result = -1;
int substr_len = 0;
int i = 0;
for(int i=0; str[i] != '\0'; i++)
{
if(isdigit(str[i]))
{
substr_len++;
}
else
{
substr_len=0;
}
if(substr_len == n)
{
result = i;
break;
}
}
return result;
}
(I just hacked this down here and now, not tested, but you get the idea. This is most likely the fastest algorithm for the task, that is, if performance matters at all)
Alternative use of sscanf()
(blatant variation of #unwind)
const char *str_in = "abcgfg0123456789gfggf";
int n1 = 0;
int n2 = 0;
// %*[^0-9] Scan any non-digits. Do not store result.
// %n Store number of characters read so far.
// %*[0-9] Scan digits. Do not store result.
sscanf(str_in, "%*[^0-9]%n%*[0-9]%n", &n1, &n2);
if (n2 == 0) return 0;
return n2 - n1;
Counts leading 0 characters as part of digit count.
Should one wish to avoid sscanf()
char str_in[] = "abcgfg1234567890gfggf";
const char *p1 = str_in;
while (*p1 && !isdigit(*p1)) p1++;
const char *p2 = p1;
while (isdigit(*p2)) p2++;
result = p2 - p1;
for testing a suit of "0123456789" inside a string you can do something like that:
int main()
{
char str_in[] = "abcgfg1234567890gfggf";
char cset[] = "1234567890";
int result;
int i;
int f;
i = 0;
f = 0;
while (str_in[i])
{
if (str_in[i] == cset[f])
{
f++;
if(f == strlen(cset))
return (f);
}
else
f = 0;
i++;
}
}

Loop crashing in C

I'm very new to C and I'm still learning the basics. I'm creating an application that reads in a text file and breaks down the words individually. My intention will be to count the amount of times each word occurs.
Anyway, the last do-while loop in the code below executes fine, and then crashes. This loop prints memory address to this word (pointer) and then prints the word. It accomplishes this fine, and then crashes on the last iteration. My intention is to push this memory address into a singly linked list, albeit once it's stopped crashing.
Also, just a quick mention regarding the array sizes below; I yet figured out how to set the correct size needed to hold the word character array etc because you must define the size before the array is filled, and I don't know how to do this. Hence why I've set them to 1024.
#include<stdio.h>
#include<string.h>
int main (int argc, char **argv) {
FILE * pFile;
int c;
int n = 0;
char *wp;
char wordArray[1024];
char delims[] = " "; // delims spaces in the word array.
char *result = NULL;
result = strtok(wordArray, delims);
char holder[1024];
pFile=fopen (argv[1],"r");
if (pFile == NULL) perror ("Error opening file");
else {
do {
c = fgetc (pFile);
wordArray[n] = c;
n++;
} while (c != EOF);
n = 0;
fclose (pFile);
do {
result = strtok(NULL, delims);
holder[n] = *result; // holder stores the value of 'result', which should be a word.
wp = &holder[n]; // wp points to the address of 'holder' which holds the 'result'.
n++;
printf("Pointer value = %d\n", wp); // Prints the address of holder.
printf("Result is \"%s\"\n", result); // Prints the 'result' which is a word from the array.
//sl_push_front(&wp); // Push address onto stack.
} while (result != NULL);
}
return 0;
}
Please ignore the bad program structure, as I mentioned, I'm new to this!
Thanks
As others have pointed out, your second loop attempts to dereference result before you check for it being NULL. Restructure your code as follows:
result = strtok( wordArray, delims ); // do this *after* you have read data into
// wordArray
while( result != NULL )
{
holder[n] = *result;
...
result = strtok( NULL, delims );
}
Although...
You're attempting to read the entire contents of the file into memory before breaking it up into words; that's not going to work for files bigger than the size of your buffer (currently 1K). If I may make a suggestion, change your code such that you're reading individual words as you go. Here's an example that breaks the input stream up into words delimited by whitespace (blanks, newlines, tabs, etc.) and punctuation (period, comma, etc.):
#include <stdio.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char buffer[1024];
int c;
size_t n = 0;
FILE *input = stdin;
if( argc > 1 )
{
input = fopen( argv[1], "r");
if (!input)
input = stdin;
}
while(( c = fgetc(input)) != EOF )
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
fclose(input);
return 0;
}
No warranties express or implied (having pounded this out before 7:00 a.m.). But it should give you a flavor of how to parse a file as you go. If nothing else, it avoids using strtok, which is not the greatest of tools for parsing input. You should be able to adapt this general structure to your code. For best results, you should abstract that out into its own function:
int getNextWord(FILE *stream, char *buf, size_t bufsize)
{
int c;
size_t n = 0;
while(( c = fgetc(input)) != EOF && n < bufsize)
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buf[n] = 0;
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
if (n == 0)
return 0;
else
return 1;
}
and you would call it like
void foo(void)
{
char word[SOME_SIZE];
...
while (getNextWord(inFile, word, sizeof word))
{
do_something_with(word);
}
...
}
If you expect in your do...while code, that result could be null (this is the condition for loop break), how do you think this code-line:
holder[n] = *result;
must work? It seems to me, that it is the reason for crashing in your program.
Change do while loop to while
use
while (condition)
{
}
instead of
do {
}while(condition)
It is crashing because you are trying to derefrance a NULL pointer result in do while loop.
I work mostly with Objective-C and was just looking at your question for fun, but I may have a solution.
Before setting n=0; after your first do-while loop, create another variable called totalWords and set it equal to n, totalWords can be declared anywhere within the file (except within one of the do-while loops), but can be defined at the top to the else block since its lifetime is short:
totalWords = n;
then you can set n back to zero:
n = 0;
Your conditional for the final do-while loop should then say:
...
} while (n <= ++totalWords);
The logic behind the application will thus say, count the words in the file (there are n words, which is the totalWords in the file). When program prints the results to the console, it will run the second do-while loop, which will run until n is one result past the value of totalWords (this ensures that you print the final word).
Alternately, it is better practice and clearer for other programmers to use a loop and a half:
do {
result = strtok(NULL, delims);
holder[n] = *result;
wp = &holder[n];
printf("Pointer value = %d\n", wp);
printf("Result is \"%s\"\n", result);
//sl_push_front(&wp); // Push address onto stack.
if (n == totalWords) break; // This forces the program to exit the do-while after we have printed the last word
n++; // We only need to increment if we have not reached the last word
// if our logic is bad, we will enter an infinite loop, which will tell us while testing that our logic is bad.
} while (true);

read string of character and assign it to an array

I don't know how to work with scanf and get the input of it for the entry of the function readBigNum I want to make array until the user entered the Enter and also I want to write a function for assigning it into an array and return the size of the large number
I want readBigNum to exactly have the char *n but I can not relate it in my function
#include <stdio.h>
int readBigNum(char *n)
{
char msg[100],ch;
int i=0;
while((ch=getchar())!='\n')
{
if(ch!='0'||ch!='1'||ch!='2'||ch!='3'||ch!='4'||ch!='5'||ch!='6'||ch!='7'||ch!='8'||ch!='9')
return -1;
msg[i++]=ch;
}
msg[i]='\0';
i=0;
return i;
}
int main()
{
const char x;
const char n;
n=scanf("%d",x);
int h=readBigNum(&n);
printf(h);
}
If I understand your question correctly, you want to implement a function that will read numbers from stdin storing them in a buffer. If a non-number is encountered, you want to return -1. If a new-line is encountered, you want to return the number of characters that were read. If that's correct, you'll probably want your code to look something like the following:
#include <stdio.h>
int readBigNum(char* n)
{
char ch;
int i=0;
while ((ch = getchar()) != '\n') {
if (ch < '0' || ch > '9') {
return -1;
}
n[i++] = ch;
}
n[i] = '\0';
return i;
}
int main(void) {
char buf[100];
int bytes = readBigNum(buf);
printf("%s\n", buf);
printf("%d\n", bytes);
};
The main differences from your implementation
The array to be populated is initialized in main and passed to the readBigNum function. This is a little simpler than having the function control the memory, in which case you would need likely need to deal with malloc and free. Even with this, you run the risk of a buffer overrun and will likely want to take additional precautions to prevent that.
The function does not set i to 0 before returning it. The original code could never return a value other than -1 (on error) or 0, which didn't appear to be the intent.
This code doesn't use scanf. Given your description of what you wanted to accomplish, using scanf didn't appear to be a good fit, however if you provide more information on why you were calling it might help to inform this answer.
The printf call was incorrect, it has been updated to print the number of bytes returned, and an additional printf call was added to print the updated buffer.
Remember that getchar() returns type int, not char. This is because the function may return EOF (which is defined as a negative integer with no particular value).
Also, for functions that deal with buffers, it is always a good idea to take an extra argument that describes the size of the array. This helps reduce buffer overruns because you know how far you can go. With your existing function, if the user types more than 100 characters, your buffer is overrun.
#include <stdio.h>
#include <ctype.h>
int readBigNum(char *n, size_t len)
{
int ch;
int i = 0;
// we make sure 'i' is less than 'len - 1' to leave space for '\0'
while((ch = getchar()) != EOF && i < (len - 1))
{
if (ch == '\n') // stop on linefeed
break;
else if (!isdigit(ch))) // abort on invalid character
return -1;
else
n[i++] = (char) ch;
}
msg[i] = '\0';
return i;
}
int main(void)
{
char buf[100];
int result = readBigNum(buf, sizeof buf);
if (result > 0)
printf("Length %d : %s\n", result, buf);
else
printf("Invalid number!\n");
}

Resources