I have a basic algorithm i want to try out, and to do so i have a txt file with a number of inputs. To do so i redirect the stdin to my input.txt using the command, in the compiler: ./prog < input.txt. Here's the mentioned code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void ExA(int n, int VALOR, int *sequencia){
int i,j,z,soma;
printf("%d - %d - %d\n",sequencia[0],sequencia[1],sequencia[2]);
for(i=1; i<=n; i++){
for(j=i; j<=n; j++){
soma = 0;
for(z=i; z<=j; z++){
soma = soma + sequencia[j];
}
if(soma == VALOR){
printf("SUBSEQUENCIA NA POSICAO %d\n", i);
return;
}
}
}
printf("SUBSEQUENCIA NAO ENCONTRADA\n");
}
int main(void){
int n, i, VALOR;
int *sequencia = malloc(sizeof(int));
char *buffer = malloc(sizeof(int) * 4);
while(read(0, buffer ,sizeof(buffer))){
sscanf(buffer,"%d %d",&n ,&VALOR);
if(n == 0 && VALOR == 0){
return 0;
}
else{
for(i = 0; i<n; i++){
read(0, buffer ,sizeof(buffer));
sscanf(buffer,"%d",&sequencia[i]);
}
}
ExA(n,VALOR,sequencia);
}
return 0;
}
The main function is responsible for reading from the input file and sending the values to the algorithm ExA. In my input.txt file i start with the following:
3 5
1
3
4
4 5
1
5
4
2
However when i print out my array (in the beginning of the ExA function) where the numbers should be stored it prints out 1 - 4 - 5 instead of the wanted 1 - 3 - 4
Note that read() does not deal with strings — it does not add a null terminator to what it reads. You are, therefore, passing sscanf() a byte array and not a guaranteed (null terminated) string.
Also, read() pays no attention whatsoever to line breaks. It reads 4 or 8 bytes at a time (unless you're on a very unusual machine these days) because sizeof(buffer) is the size of a pointer. Assuming you have a 64-bit machine, the first read() processes the first 3 lines (3 5, 1, 3 — they happen to be 8 bytes long); the second read() gets the second 3 lines (4, 4 5, 1) and reports appropriately.
You should capture and test the return value from read(). You should print what it gets. (Partially fixed code — more work to be done to get the program fully working.)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void ExA(int n, int VALOR, int *sequencia)
{
int i, j, z, soma;
printf("%d - %d - %d\n", sequencia[0], sequencia[1], sequencia[2]);
for (i = 1; i <= n; i++)
{
for (j = i; j <= n; j++)
{
soma = 0;
for (z = i; z <= j; z++)
{
soma = soma + sequencia[j];
}
if (soma == VALOR)
{
printf("SUBSEQUENCIA NA POSICAO %d\n", i);
return;
}
}
}
printf("SUBSEQUENCIA NAO ENCONTRADA\n");
}
int main(void)
{
int n, i, VALOR;
int *sequencia = malloc(sizeof(int));
char *buffer = malloc(sizeof(int) * 4);
while (read(0, buffer, sizeof(buffer)))
{
sscanf(buffer, "%d %d", &n, &VALOR);
if (n == 0 && VALOR == 0)
{
return 0;
}
else
{
for (i = 0; i < n; i++)
{
int nbytes = read(0, buffer, sizeof(buffer));
printf("Read [%.*s]\n", nbytes, buffer);
buffer[nbytes] = '\0';
sscanf(buffer, "%d", &sequencia[i]);
}
}
ExA(n, VALOR, sequencia);
}
return 0;
}
Given the input shown in the question, I get the output:
Read [4
4 5
1
]
Read [5
4
2
]
[]
4 - 5 - 5
SUBSEQUENCIA NA POSICAO 1
This much work cleans up the code — and explains some of the odd result you were getting. It doesn't make full use of the space allocated (which is bigger than sizeof(buffer), so the buffer[nbytes] = '\0'; assignment is within bounds of the array. It reads the same value repeatedly in the sscanf() call because you don't tell it to read from different locations in the string. If you need to read multiple values from a buffer using scanf(), read the answers about How to use sscanf() in a loop?
You should consider using fgets() or maybe POSIX getline() to read lines. If you're sure the data is clean, you could even use scanf() directly, but it is usually better to read lines and then parse them with sscanf().
If the exercise requires you to read with the read() system call, then you will have to work out a scheme where you read a buffer full of data and dole the contents out in chunks.
Related
I wrote a program that scans an unknown amount of integers into an array but when I run it, it print the last value it has gotten an infinite amount of times.
For example for the input: 1 2 3 4 5
The output would be 55555555555555555555555...
Why does this happen and how can I fix that?
My goal here is to create a array, for an instance {1, 2, 3, 4, 5} and then print what it scanned into the array, ONLY ONCE...
int *pSet = (int*) malloc(sizeof(int)); int i; int c;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
scanf("%d", &c);
pSet[0] = c;
printf("%d ", c);
for(i = 1; c != EOF; i++) {
pSet = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSet == NULL) {
return FAIL;
}
scanf("%d", &c);
pSet[i] = c;
printf("%d ", c);
}
free(pSet);
Why does this happen (?) (print ... an infinite amount of times.)
Look at the loop terminating conditions c != EOF.
int c;
scanf("%d", &c);
for(i = 1; c != EOF; i++) { // Not good code
scanf("%d", &c);
}
EOF is some negative value, often -1. scanf("%d", &c) attempts to read user input and convert to an int. scanf() returns a 1,0,EOF depending on if it 1) succeeded, 2) failed to find numeric text or 3) end-of-file or input error occurred. Unfortunately code does not use that return value. Instead code used the number read, c and checked if that number read was the same as EOF.
how can I fix that?
Only loop when the return value of scanf() is as expected (1).
for(i = 1; scanf("%d", &c) == 1; i++) {
...
}
Putting this together with some other ideas
#include <stdio.h>
#include <stdio.h>
int main(void) {
printf("Please enter a stream of numbers to make a set out of them:\n");
int *pSet = NULL; // Start with no allocation
size_t i = 0;
int c;
for (i = 0; scanf("%d", &c) == 1; i++) {
// +--------------------------- No cast needed.
// v v----------v Use sizeof de-referenced pointer
void *p = realloc(pSet, sizeof *pSet * (i + 1));
if (p == NULL) {
free(pSet);
return EXIT_FAILURE;
}
pSet = p;
pSet[i] = c;
}
for (size_t j = 0; j < i; j++) {
printf("%d ", pSet[j]);
}
free(pSet);
return 0;
}
There are a number of problems.
1) Terminate the loop when scanf fails instead of using EOF. Do that by checking that the return value is 1 (i.e. the number of input items
successfully matched)
2) Don't allocate memory until it's needed
3) Never do realloc directly into the target pointer - always use a temp variable.
Fixing this your code could be:
#include <stdio.h>
int main(void) {
int *pSet = NULL;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
int i = 0;
int c;
while (1) {
if (scanf("%d", &c) != 1)
{
printf("Terminating input loop\n");
break;
}
int* tmp = realloc(pSet, sizeof(int)*(i+1));
if(tmp == NULL) {
printf("oh dear...\n");
break;
}
pSet = tmp;
pSet[i++] = c;
printf("%d ", c);
}
for (int j=0; j < i; ++j) printf("%d\n", pSet[j]);
free(pSet);
return 0;
}
Input:
1 2 3 4 5 6 7 stop
Output:
Please enter a stream of numbers to make a set out of them:
1 2 3 4 5 6 7
Terminating input loop
1
2
3
4
5
6
7
You should stop your loop when scanf fails. According to the manual:
On success, [scanf] return[s] the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs. [...]
So you can turn your for loop into a while one.
#include <stdio.h>
#include <stdlib.h>
#define FAIL 0
int main() {
int *pSet = (int*) malloc(sizeof(int));
int c;
int i=0;
printf("Please enter a stream of numbers to make a set out of them: ");
while(scanf("%d", &c) == 1) {
pSet[i] = c;
pSetNew = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSetNew == NULL) {
free(pSet);
return FAIL;
} else {
pSet = pSetNew;
}
printf("%d ", c);
i++;
}
free(pSet);
}
But if you want a more robust piece of code, I suggest you to retrieve the answer as a string (NULL-terminated array of char), and then parse it with dedicated functions like strtol which let you check if the whole string is a valid entry, and not only the first characters.
Note: HengLi fixed a potential memory leak in the code sample above
I am using user input to fill a 2d array. A user inputs numbers in one line and I then use nested loops to fill the array like so:
//User inputs: "1 2 3 4 5"
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
scanf("%d", &arr[i][j]);
}
}
However, the problem is if the user enters 5 ints when there is room for 6, it just waits for another input. How can I detect if there are insufficient numbers?
I have tried using this but it didn't work:
for(i = 0; i < r; i++){
for(j = 0; j < c; j++){
if (!feof(stdin)){
scanf("%d", &arr[i][j]);
}
else{
printf("insufficient datapoints\n");
}
}
}
One way to accomplish your goal would involve using fgets() instead of scanf() to read in a line of input at a time. Then strtok() can be used to break the line of input into tokens, and strtol() can be used to parse the tokens into numbers. Compared with scanf(), it is much easier to use fgets to handle unstructured user input.
The code below does this. If there are too many elements on an input row, too few elements, or if one of the elements is not a valid number, a message is printed and the row must be entered again.
As each line is entered by the user, strtok() is used to break the line into tokens. The list of token delimiters is stored in delims[]. Note that tokens may be separated by spaces or tabs; the delimiters themselves are not part of the token, so including \r and \n ensures that these characters will not be part of the final token in a line.
When a token is found, strtol() is used to convert it to an integer, if possible. After the call to strtol(), the pointer tail points to the first character in the token that was not part of a number; if tail points to the NUL terminator, then the entire string was parsed as a number, otherwise the input is considered bad and the row must be entered again.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 1000
int main(void)
{
size_t r = 3;
size_t c = 5;
size_t i, j;
char buffer[BUF_SIZE];
char *token;
char *tail;
const char delims[] = " \t\r\n";
int arr[r][c];
int temp_val;
printf("Enter rows of %zu data elements:\n", c);
for(i = 0; i < r; i++){
j = 0;
if (fgets(buffer, BUF_SIZE, stdin) == NULL) {
perror("Error in fgets()");
exit(EXIT_FAILURE);
}
token = strtok(buffer, delims);
while (token != NULL) {
temp_val = strtol(token, &tail, 10);
if (*tail == '\0') {
arr[i][j] = temp_val;
++j;
} else { // token not a valid number
j = 0;
break;
}
if (j > c) { // too many input values
break;
}
token = strtok(NULL, delims);
}
if (j != c) {
printf("insufficient datapoints\n");
--i; // enter row again
}
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%5d", arr[i][j]);
}
putchar('\n');
}
return 0;
}
Sample interaction:
Enter rows of 5 data elements:
1 2 3 4
insufficient datapoints
1 2 3 4 5 6
insufficient datapoints
1 x 2 3 4
insufficient datapoints
1 2 3 4 x
insufficient datapoints
1 2 3 4 5 x
insufficient datapoints
1 2x 3 4 5
insufficient datapoints
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
You can use peek ahead in the stream and test characters before you actually consume them. (Well sort of in c).
You can use this to ignore whitespace (you will need to do this).
You can also use this peeked value to indicate if insufficient characters have been input.
The peek needs to be done BEFORE the actual read (scanf).
Added rough example code below
#include <stdio.h>
#include <ctype.h>
int r=3;
int c=2;
int arr[100][100]; // FIX magic
int main(int argc, char** argv[]) {
for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
if (feof(stdin)) {
// error check and error / normal exit etc.
printf("eof\n");
}
char c=getchar();
if (c=='\n') {
// error check and error / normal exit here
printf("newline\n");
} else if (isspace(c)) {
// advance and remove them - watch for end of stream when winding
printf("advance and discard whiitespace\n");
} else { // add check for isdigit
// push back
ungetc(c, stdin);
printf("ungetc\n");
}
scanf("%d", &arr[i][j]);
printf("got %d\n", arr[i][j]);
}
}
return 0;
}
I would like use scanf() to read the following table:
Q 1 3
U 2 6
Q 2 5
U 4 8
This is my code:
#include <stdio.h>
#include <stdlib.h>
void main() {
int *a;
int i, j;
a = (int *) malloc(4 * 3 *sizeof(int));
printf("input:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < 3; j++) {
scanf("%d", a + 3 * i + j);
}
}
printf("output:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < 3; j++) {
printf("%d ", a[3*i+j]);
}
printf("\n");
}
}
However, when I input the first line Q 1 3, this program end. I don't know why?
This happens because you provided a non-numeric input to your program that wants to read a number with %d. Since Q is not a number, scanf fails.
However, your program is not paying attention to the return value of scanf, and keeps calling it in the failed state. The program thinks that it is getting some data, while in fact it does not.
To fix this, change the code to pass %c or %s when it reads the non-numeric character, check the return value of scanf, and get rid of invalid input when scanf fails.
When you call scanf, it returns how many values corresponding to % specifiers it has provided. Here is how to check the return value of scanf:
if (scanf("%d", a + 3 * i + j) == 1) {
... // The input is valid
} else {
fscanf(f, "%*[^\n]"); // Ignore to end of line
}
It's because the letter Q is not a number, so scanf will fail and leave the input buffer untouched. So the next iteration scanf will see the same Q and again fail, and so on and on and on...
That will mean nothing is actually read into the memory you allocate, and you print out the uninitialized memory, leading to undefined behavior.
One possible way to solve your problem might be to read lines instead (using e.g. fgets), and then use sscanf to parse the whole line in one go. Perhaps something like
for (i = 0; i < 4; i++) {
char buffer[64];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
char c; // The character
int a, b; // The integer values
sscanf(buffer, "%c %d %d", &c, &a, &b);
a[3 * i + 0] = c;
a[3 * i + 1] = a;
a[3 * i + 2] = b;
}
}
I also recommend you actually initialize the memory you allocate, especially if you're not going to use parts of it but still print it out.
Either use scanf() with int variable with proper ASCII value or use scanf() with char variable for character but print with %c in both cases. ASCII code for Q is 81 and for U it is 85.
I'm a programming noob so please bear with me.
I'm trying to read numbers from a text file into an array. The text file, "somenumbers.txt" simply holds 16 numbers as so "5623125698541159".
#include <stdio.h>
main()
{
FILE *myFile;
myFile = fopen("somenumbers.txt", "r");
//read file into array
int numberArray[16];
int i;
for (i = 0; i < 16; i++)
{
fscanf(myFile, "%d", &numberArray[i]);
}
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", numberArray[i]);
}
}
The program doesn't work. It compiles but outputs:
Number is: -104204697
Number is: 0
Number is: 4200704
Number is: 2686672
Number is: 2686728
Number is: 2686916
Number is: 2004716757
Number is: 1321049414
Number is: -2
Number is: 2004619618
Number is: 2004966340
Number is: 4200704
Number is: 2686868
Number is: 4200798
Number is: 4200704
Number is: 8727656
Process returned 20 (0x14) execution time : 0.118 s
Press any key to continue.
change to
fscanf(myFile, "%1d", &numberArray[i]);
5623125698541159 is treated as a single number (out of range of int on most architecture). You need to write numbers in your file as
5 6 2 3 1 2 5 6 9 8 5 4 1 1 5 9
for 16 numbers.
If your file has input
5,6,2,3,1,2,5,6,9,8,5,4,1,1,5,9
then change %d specifier in your fscanf to %d,.
fscanf(myFile, "%d,", &numberArray[i] );
Here is your full code after few modifications:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *myFile;
myFile = fopen("somenumbers.txt", "r");
//read file into array
int numberArray[16];
int i;
if (myFile == NULL){
printf("Error Reading File\n");
exit (0);
}
for (i = 0; i < 16; i++){
fscanf(myFile, "%d,", &numberArray[i] );
}
for (i = 0; i < 16; i++){
printf("Number is: %d\n\n", numberArray[i]);
}
fclose(myFile);
return 0;
}
for (i = 0; i < 16; i++)
{
fscanf(myFile, "%d", &numberArray[i]);
}
This is attempting to read the whole string, "5623125698541159" into &numArray[0]. You need spaces between the numbers:
5 6 2 3 ...
Loop with %c to read the stream character by character instead of %d.
There are two problems in your code:
the return value of scanf must be checked
the %d conversion does not take overflows into account (blindly applying *10 + newdigit for each consecutive numeric character)
The first value you got (-104204697) is equals to 5623125698541159 modulo 2^32; it is thus the result of an overflow (if int where 64 bits wide, no overflow would happen). The next values are uninitialized (garbage from the stack) and thus unpredictable.
The code you need could be (similar to the answer of BLUEPIXY above, with the illustration how to check the return value of scanf, the number of items successfully matched):
#include <stdio.h>
int main(int argc, char *argv[]) {
int i, j;
short unsigned digitArray[16];
i = 0;
while (
i != sizeof(digitArray) / sizeof(digitArray[0])
&& 1 == scanf("%1hu", digitArray + i)
) {
i++;
}
for (j = 0; j != i; j++) {
printf("%hu\n", digitArray[j]);
}
return 0;
}
enter your file input like this
ex:
12
13
22
45
(after every number hit enter)
then run your programm it will run properly
I want to make a program which reads the text from a file and shows every character, the ASCI code of each one and the number of occurrences.
I wrote this but it doesn't show the occurrences.
#include <stdio.h>
#include <stdlib.h>
int main ()
{
FILE * pFile;
int i=0;
int j=0;
char text[j];
int ascii[256];
int occ[256];
int occurance=0;
int position;
pFile = fopen ("c:/1.in","r");
if (pFile==NULL) perror ("Error opening file");
else
{
while (!feof(pFile)) {
j++;
text[j]=getc (pFile);
ascii[j]= (int) text[j];
position=ascii[j];
occ[position]++;
}
for (i=1;i<j;i++){
occurance=position[i]
printf ("Chracter %c has ascii %d and occurs %d times \n", text[i],ascii[i],occ[occurance] );}
}
system("PAUSE");
return 0;
}
First, I don't see the point in this:
int j=0;
char text[j];
If you want to put every character in the file into an array then read the size of the file and malloc() the correct size to a pointer. But why do that anyway? If you're trying to count ever occurrence of ever character then just keep track of the possibilities.
For completeness you can use an array of 256 characters, but in reality if you're just looking at standard printable characters there should only be about 94.
This:
int main ()
{
int temp = 0, i;
int occ[256] = {0};
FILE * pFile = fopen("test.txt", "r");
if (pFile == NULL) perror("Error opening file");
else {
while (!feof(pFile)) {
temp = getc(pFile);
if((temp < 255) && (temp >= 0))
occ[temp]++;
}
}
//reads every character in the file and stores it in the array, then:
for(i = 0; i<sizeof(occ)/sizeof(int); i++){
if(occ[i] > 0)
printf(" Char %c (ASCII %#x) was seen %d times\n", i, i, occ[i]);
}
return 0;
}
will print every character, the ASCII code (in hex) and the number of times it showed.
An example input file of:
fdsafcesac3sea
yeilds an output of:
Char 3 (ASCII 0x33) was seen 1 times
Char a (ASCII 0x61) was seen 3 times
Char c (ASCII 0x63) was seen 2 times
Char d (ASCII 0x64) was seen 1 times
Char e (ASCII 0x65) was seen 2 times
Char f (ASCII 0x66) was seen 2 times
Char s (ASCII 0x73) was seen 3 times
Below simple logic works fine for me. Add file operations to get the buf.
int main()
{
char buf[] = "abcaabde";
char val[256] = {0};
int i = 0;
for (i = 0; i < sizeof(buf); i++)
{
val[buf[i]]++;
}
for (i = 0; i < 256; i++)
{
if (val[i] != 0)
{
printf("%c occured %d times\n", i, val[i]);
}
}
return 0;
}
Output is
occured 1 times
a occured 3 times
b occured 2 times
c occured 1 times
d occured 1 times
e occured 1 times