Strok spaces using buffer/dynamic memory - c

how could I strtok at spaces while reading in data from a buffer? If my text file contained
1 23 50
45 50 30
2 15 30
and I decide to print the array with my code below, it will print line by line. How could I extend this to further divide the array into individual numbers for each index of the array? Eg.
1
23
50, etc...
I've tried playing around with strtok but I keep segfaulting and I wasn't sure where to fix it.
FILE * fp;
char buffer[5000];
int size = 0;
char **entireFile = NULL;
fp = fopen("file.txt","r");
entireFile = malloc(sizeof(buffer) * sizeof(char*));
while (fgets(buffer,5000,fp)!= NULL)
{
entireFile[size] = malloc(strlen(buffer)+1);
strcpy(entireFile[size],buffer);
size++;
}

I want entireFile[0] = 1, entireFile1 = 23
This can easily be accomplished with fscanf. Here is a pretty good reference for scanning in inputs.
#include <stdio.h>
int main(){
FILE *in = fopen("in.txt" , "r");
int hold;
/* Won't actually store values, but can be used for
value manipulation inbetween */
while ( fscanf(in, "%d", &hold) != EOF ){
printf("Scanned in %d\n", hold);
}
fclose(in);
return 0;
}
If you want this in an array form, add an incrementing integer and change the hold to an array.
#include <stdio.h>
int main(){
FILE *in = fopen("in.txt" , "r");
int hold[100], i=0; // Hold a maximum of 100 integers
while ( fscanf(in, "%d", &hold[i]) != EOF ){
printf("Scanned in %d\n", hold[i++]);
}
fclose(in);
return 0;
}
You could also do dynamic memory allocation like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
FILE *in = fopen("in.txt", "r");
int i=0, j;
char* fragments[2000];
char entry[100];
while ( fscanf(in, "%s", &entry[i]) != EOF ){
fragments[i] = malloc(sizeof(char) * (1 + strlen(entry)));
strcpy(fragments[i], &entry[i]);
i++;
}
for ( j = 0; j < i; j++ ){
printf("%s\n", fragments[j]);
}
fclose(in);
return 0;
}

This will read 1, 2, or 3 numbers on each line of your file. It uses the return value from sscanf to see how many numbers were read from each line. Of course, if there is any rogue non-numerical data, it will mess up.
#include <stdio.h>
int main(void)
{
FILE *fp;
int a, b, c;
int res;
char str [100];
if ((fp = fopen("file.txt", "rt")) == NULL)
return 1;
while(fgets(str, sizeof str, fp) != NULL) {
res = sscanf(str, "%d%d%d", &a, &b, &c);
if (res == 3)
printf ("3 values %d %d %d\n", a, b, c);
else if (res == 2)
printf ("2 values %d %d\n", a, b);
else if (res == 1)
printf ("1 value %d\n", a);
else
printf ("0 values\n");
}
fclose(fp);
return 0;
}
File content:
1 23 50
45 50 30
2 15 30
10 20
100
Program output:
3 values 1 23 50
3 values 45 50 30
3 values 2 15 30
2 values 10 20
0 values
1 value 100

Related

can someone explain this code how to split the string without using strtok?

void filename()
{
char c[50];
FILE *fp;
char d;
int i;
int s[5];
printf("Enter the file name: ");
scanf("%s", c);
fp = fopen(c, "r");
count = 0;
fscanf(fp, "%d$", &id[count]);
while(!feof(fp))
{
fscanf(fp, "%[^$]s)", names[count]);
for(i = 0; i < 5; i++)
{
fscanf(fp, "%c", &d);
fscanf(fp, "%d", &s[i]);
}
grades[count] = ((double)s[0] * 0.15 + (double)s[1] * 0.15 + (double)s[2] * 0.25 + (double)s[3] * 0.1 + (double)s[4] * 0.35);
count++;
fscanf(fp, "%d$", &id[count]);
}
fclose(fp);
}
Please explain to me how to split a string without using strtok
like this fscanf(fp, "%[^$]s)", names[count]);
How can I do that?
There are a lot of issues with your code. You are using feof incorrectly. You must always add a width modifier to a conversion specifier that reads a string. You must check the value returned by scanf to ensure that it successfully matched input. I've tried to make minimal changes to the format strings you've used to demonstrate the form of the input that seems to be expected. Perhaps the reads into the unused character 'd' were attempts to match $, but that is not imposed in your code (I've inserted d in the input to be read by the fscanf(fp, "%c", &d)). Since you've not provided a sample of the expected input, I've made some assumptions. If the input shown below does not match your expected input, you should modify your format strings. I am guessing you did not intend to match the literal s), but your current code requires those be in the input. Rather than more longwinded and probably poorly worded attempts at explanation:
$ gcc a.c
$ cat input
1$Alice $s)d 10d 5d 10d 15d 7
2$Bob $s)d 11d 6d 11d 16d 8
2$Chuck $s)d 12d 7d 12d 17d 9
$ echo input | ./a.out
Enter the file name: grade for Alice is 8.700000
grade for Bob is 9.700000
grade for Chuck is 10.700000
$ cat a.c
#include <stdio.h>
#include <stdlib.h>
int count;
int id[64];
char names[64][256];
double grades[64];
/* "filename" is a terrible name for a function that reads and parses data */
void
filename(const char *prompt)
{
char path[50];
FILE *fp;
char d;
int i;
double weight[] = { 0.15, 0.15, 0.25, 0.1, 0.35 };
printf("%s: ", prompt);
scanf("%49s", path); /* Always use a width modifier with %s!! */
if( (fp = fopen(path, "r")) == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
count = 0;
while(
count < 64
&& 1 == fscanf(fp, "%d$", id + count)
&& 1 == fscanf(fp, "%255[^$]$s)", names[count])
){
grades[count] = 0;
for(i = 0; i < 5; i++) {
int s;
if( 0
|| 1 != fscanf(fp, "%c", &d)
|| 1 != fscanf(fp, "%d", &s)
){
fprintf(stderr, "Unexpected input\n");
goto end;
}
grades[count] += (double)s * weight[i];
}
printf("grade for %s is %f\n", names[count], grades[count]);
count += 1;
}
end:
fclose(fp);
}
int
main(void)
{
filename("Enter the file name");
return 0;
}
I would guess that your intent was to do something more like:
$ cat input2
1$Alice$ 10 $ 5 $ 10 $ 15 $ 7
2$Bob$ 11 $ 6 $ 11 $ 16 $ 8
3$Chuck$ 12 $ 7 $ 12 $ 17 $ 9
which could be parsed with:
#include <stdio.h>
#include <stdlib.h>
int count;
int id[64];
char names[64][256];
double grades[64];
void
parse_file(FILE *fp)
{
double weight[] = { 0.15, 0.15, 0.25, 0.1, 0.35 };
count = 0;
while(
count < 64
&& 1 == fscanf(fp, "%d", id + count)
&& 1 == fscanf(fp, "$ %255[^$]", names[count])
){
grades[count] = 0;
for( int i = 0; i < 5; i += 1 ){
int s;
if( 1 != fscanf(fp, " $%d", &s) ){
fprintf(stderr, "Unexpected input\n");
exit(EXIT_FAILURE);
}
grades[count] += (double)s * weight[i];
}
printf("grade for %s is %f\n", names[count], grades[count]);
count += 1;
}
}
int
main(int argc, char **argv)
{
const char *path = argc > 1 ? argv[1] : NULL;
FILE *fp = path ? fopen(path, "r") : stdin;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
parse_file(fp);
fclose(fp);
return EXIT_SUCCESS;
}
Please note that this is functional, but certainly should not be considered robust. (For example, if there's a line with extra $ at the end, the program will merely abort with no error message.) It's not at all clear what behavior you want, so I'm not going to modify that but will merely remark that scanf is absolutely the wrong tool for this. It is merely a toy that should only be used for educational purposes. Sadly, it should never be used for educational purposes, but is really just a toy to be used to confuse newbies. Please read http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html

reading unknown number of of integers and printing them in words

I'm trying to process input from stdin but keep running into walls.
My goal is to read a strem of numbers(0-99) and print each one in words.
My first attempt was:
int main(void) {
char *a[20] = {"zero","one","two","three","four","five","six","seven","eight",
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[8] = {"twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"};
int num=0, tens=0, ones=0;
while (scanf("%d", &num)==1){
tens = num/10;
ones = num%10;
if (tens>1){
printf("%s ", b[tens-2]);
printf("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}
printf("done");
return 0;
}
Output is correct but scanf never terminates the loop.
Second attempt:
int main(void) {
char *a[20] = {"zero","one","two","three","four","five","six","seven","eight",
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[8] = {"twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"};
char line[1024], *ptr = NULL;
long num;
int tens=0, ones=0;
if(fgets(line, sizeof(line), stdin)!=NULL){
do {
num = strtol(line, &ptr, 10);
tens = num/10;
ones = num%10;
if (tens>1){
printf("%s ", b[tens-2]);
printf("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}while (*ptr!= '\n');
}
printf("done");
return 0;
}
Here I get a compilation error and can't find the problem so I don't know if it works.
[UPDATE]: The second code runs but for an input of more then one number like
12 35 51 it prints the first number (twelve) infinitely.
Any help would be greatly appreciated.
You are so close. You just need to validate the return of strtol, and update the pointer address based on the endptr following the call to strtol. You should also check for values outside the range of your conversion as mentioned in the discussion. This is all that is needed:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
char *a[] = {"zero","one","two","three","four","five","six",
"seven","eight","nine","ten","eleven","twelve",
"thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[] = {"twenty","thirty","fourty","fifty","sixty",
"seventy","eighty","ninety"};
char line[1024] = "";
long num;
int tens=0, ones=0;
if (fgets (line, sizeof(line), stdin) != NULL) {
char *p = line, *ep = NULL;
errno = 0;
while (errno == 0) {
num = strtol (p, &ep, 10); /* convert to long */
if (p == ep) break; /* no digits, break */
p = ep; /* update p to ep */
if (num < 0 || 99 < num) { /* validate range */
fprintf (stderr, "error: %ld - out of range.\n", num);
continue;
}
tens = num/10;
ones = num%10;
if (tens > 1) {
printf ("%s ", b[tens-2]);
printf ("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}
}
printf ("done\n");
return 0;
}
Example Use/Output
$ ./bin/n2string
12 55 61 -1 33 102 4
twelve
fifty five
sixty one
error: -1 - out of range.
thirty three
error: 102 - out of range.
four
done
Look it over and let me know if you have any questions.
The purpose of the code appears to be to print the text version of a digit that was entered. Your code works almost unchanged, I just added a library and ran it.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *a[20] = {"zero","one","two","three","four","five","six","seven","eight",
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[8] = {"twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"};
char line[1024], *ptr = NULL;
long num;
int tens=0, ones=0;
if(fgets(line, sizeof(line), stdin)!=NULL){
do {
num = strtol(line, &ptr, 10);
tens = num/10;
ones = num%10;
if (tens>1){
printf("%s ", b[tens-2]);
printf("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}while (*ptr!= '\n');
}
printf("done");
return 0;
}
Test
19
nineteen
done
Maybe the problem was that you didn't know the purpose of the code.

Read numbers from a .txt file and store them in array in C

I've been trying to figure out how to read the scores and storing them in array.
been trying for sometime and its clearly not working out for me. Please help.
//ID scores1 and 2
2000 62 40
3199 92 97
4012 75 65
6547 89 81
1017 95 95//.txtfile
int readresults (FILE* results , int* studID , int* score1 , int* score2);
{
// Local Declarations
int *studID[];
int *score1[];
int *score2[];
// Statements
check = fscanf(results , "%d%d%d",*studID[],score1[],score2[]);
if (check == EOF)
return 0;
else if (check !=3)
{
printf("\aError reading data\n");
return 0;
} // if
else
return 1;
You declare variables twice, once in parameter list and once in "local declarations".
The function brace is not closed.
One fscanf can only read a number of items specified by its format string, in this case 3 ("%d%d%d"). It reads numbers, not arrays. To fill an array, you need a loop (while, or for).
EDIT
Okay, here's one way to do it:
#define MAX 50
#include <stdio.h>
int readresults(FILE *results, int *studID, int *score1, int *score2) {
int i, items;
for (i = 0;
i < MAX && (items = fscanf(results, "%d%d%d", studID + i, score1 + i, score2 + i)) != EOF;
i++) {
if (items != 3) {
fprintf(stderr, "Error reading data\n");
return -1; // convention: non-0 is error
}
}
return 0; // convention: 0 is okay
}
int main() {
FILE *f = fopen("a.txt", "r");
int studID[MAX];
int score1[MAX];
int score2[MAX];
readresults(f, studID, score1, score2);
}
If you want to call that function just once and have it read the scores for all of the students, you should use something like this:
int i=0;
check = fscanf(results , "%d %d %d",&id[i],&score1[i],&score2[i]);
while(check!=EOF){
i++;
check = fscanf(results , "%d %d %d",&id[i],&score1[i],&score2[i]);
}

Parse string " comes from a file " to integer

I am making a program in C that reads a line from file and displays this line on screen
My homework requires that the file must get a number from the file and make some operations on it.
I get the file content and put it in an array:
while ( fgets ( line, sizeof line, file ) != NULL )
{
strcpy(arra[i], line);
printf("array ----> %d \n", arra[i]);
i++;
}
how can I parse this content to int ?
If line is a char*, you can use atoi to convert it to an integer.
printf("array ----> %d \n", atoi(line));
you can use atoi()
int x = atoi("string");
From your code sample
while ( fgets ( line, sizeof line, file ) != NULL )
{
strcpy(arra[i], line);
printf("array ----> %d \n", atoi(arra[i]));
i++;
}
#include <stdio.h>
#include <stdlib.h>
#define MAX_DATA_SIZE 10
int main(){
FILE *file;
char line[128];
int array[MAX_DATA_SIZE];
int i,count,sum;
file = fopen("data.txt","r");
/* data.txt:
100
201
5
-6
0
*/
for(i=0; NULL!=fgets(line, sizeof(line), file); ++i){
if(i == MAX_DATA_SIZE){
fprintf(stderr,"exceeded the size of the array.\n");
exit(EXIT_FAILURE);
}
array[i]=atoi(line);
}
fclose(file);
/*some operations */
count = i;
sum = 0;
for(i=0;i<count;++i)
sum += array[i];
printf("%d\n",sum);
return 0;
}

Read number from a file and replace it with another number

12 23 34 45 56
34 23 56 21 43
12 57 98 34 12
The above is the content of a txt file.
With C, i can use fgetc(myFile) to get the first integer and store into an integer variable.
I will check whether it is 12.
if it is 12, i want to replace with 25. How do i exactly replace it a certain number.
How do i rewrite a certain part of it?
Or do i store every number into an array, replace all 12s with another numbers and overwrite the whole file??
Save result to another file, than renames it. This code opens homework.txt, replaces all 12 -> 25 and writes result to homework_new.txt
#include <stdio.h>
#include <string.h>
#define MAXBUF 42
#define HOMEWORKFILE "homework.txt"
#define HOMEWORKNEWFILE "homework_new.txt"
int main(int argc, char **argv)
{
char buf[MAXBUF+1];
char str[MAXBUF+1];
FILE *hw;
FILE *hw_new;
int length;
int i, j;
int number;
char is_first;
int n_line = 0;
hw = fopen(HOMEWORKFILE, "r");
hw_new = fopen(HOMEWORKNEWFILE, "w");
if (!hw)
{
fprintf(stderr, "File not found: %s\n", HOMEWORKFILE);
return 5;
}
while(!feof(hw))
if (fgets(buf, MAXBUF, hw) != NULL)
{
length = strlen(buf);
j = 0;
str[0] = 0;
is_first = 1;
n_line++;
/* parse string */
for(i = 0; i < strlen(buf); ++i)
{
if (isblank(buf[i]) || buf[i] == '\0' || buf[i] == '\n')
{
str[j] = 0;
number = atoi(str);
if (is_first)
is_first = 0;
else
fprintf(hw_new, " ");
if (number == 12)
fprintf(hw_new, "%d", 25);
else
fprintf(hw_new, "%d", number);
j = 0;
}
else if (isdigit(buf[i]))
{
str[j++] = buf[i];
}
else
{
fprintf(stderr, "bad input on line %d '%s'\n", n_line, buf);
return 100;
}
}
fprintf(hw_new, "\n");
}
fclose(hw_new);
fclose(hw);
return 0;
}
If it's a small file , to overwrite the whole file is a good idea and easier.
If it's not limited in c language, you can try powerful tools like "sed" or some script language.
Here's a list:
fgets
ftell
fseek
fputs
Note that you need to ensure the correct lengths of the data written, in order to overwrite exactly what you want.
Another option would be, as you said, to overwrite the whole file, then you also need
freopen

Resources