I'm using a for loop, which I want to iterate a number of times equal to the number of characters scanned by scanf. However, it seems to run too many times. The code was originally written to print to phrase "We are in 2019", which it does, but now I need to use it for something else. I added in the line: printf("%i",i);
to see how many times it was going through the for loop. It seems to be running 8 times for each run of the while loop, regardless of how long the word scanned was.
#include <stdio.h>
#include <stdlib.h>
int main() {
char* word = malloc(sizeof(char) * (46)); // create a char array
FILE* fp;
fp = fopen("file.txt", "w+");
fputs("We are in 2019", fp);
rewind(fp); // sets to start of file
while(fscanf(fp, "%s", word) != EOF) {
for(int i = 0; i < sizeof(word) / sizeof(word[0]); i++) {
printf("%c", word[i]);
printf("%i", i);
}
printf("\n");
}
fclose(fp);
return (0);
}
The output is:
W0e1234567
a0r1e234567
i0n1234567
200112934567
So I can see it's running the for loop 8 times for each run for each run of the while loop.
Am I misunderstanding how fscanf works? i thought it stopped at a whitespace, and only stored the preceding characters... e.g. first it would scan "We" then store it as a 3 character array in "words", then scan "are" in a 4 character array in "words" and so on. What is really happening?
It is stopping at whitespace.
Apparently you have 64 bit pointers. The variable word is a pointer, so sizeof(word) is 8. Since sizeof one character is 1, sizeof(word) / sizeof(word[0]) is 8.
So, the first time fscanf returns, it has read "We" into the buffer. Then it loops for i from 0 to 7.
i = 0
printf("%c", word[i]); //=> 'W'
printf("%i", i); //=>0
i = 1
printf("%c", word[i]); //=> 'e'
printf("%i", i); //=>1
i = 2
printf("%c", word[i]); //=> '\0' so nothing
printf("%i", i); //=>2
i = 3
printf("%i", i); //=>3
i = 4
printf("%i", i); //=>4
i = 5
printf("%i", i); //=>5
i = 6
printf("%i", i); //=>6
i = 7
printf("%i", i); //=>7
so that is how you get:
W0e1234567
You would see the desired output if your loop looked like this:
while(fscanf(fp, "%s", word) != EOF) {
puts(word);
}
sizeof(word) will not give you the size of the array. It gives the size of the pointer char *word.
It would be simpler to avoid memory allocation, and the size of the array isn't really relevant anyway.
#include <stdio.h>
#include <stdlib.h>
int main() {
char word[46]; // local array
FILE* fp = fopen("file.txt", "w+");
if(fp == NULL) {
return 1; // or better error report
}
fputs("We are in 2019", fp);
rewind(fp);
while(fscanf(fp, "%45s", word) == 1) { // restrict length, check the scan worked
for(int i = 0; word[i] != 0; i++) { // finish when the string terminator is found
printf("%c", word[i]);
}
printf("\n");
}
fclose(fp);
return 0;
}
Program output:
We
are
in
2019
Several remarks can be done on your code
by definition sizeof(char) is 1, so your malloc(sizeof(char) * (46)) can be simplified to be malloc(46). Note you can also use an array char word[46];
fscanf(fp, "%s", word) is very dangerous, if the read word longer than 45 characters you write out of word with an undefined behavior, limit the size doing fscanf(fp, "%45s", word)
As said in the remarks sizeof(word) / sizeof(word[0]) do not return the length of your word, you can just stop when word[i] is 0
to print the index just after each character do not produces a very readable result, are you sure you want that ?
why do you not directly print the word by (f)puts or printf with the format %s and get the length of the string using strlen (if you want to know it) ?
I want to iterate a number of times equal to the number of characters scanned by scanf.
scanf scans more than the number of characters in returns in the string, the spaces are bypassed silently. Only one thing is sure, when you reach the end of the file without error the number of characters scanned by scanf if the size of the file.
Related
I'm trying to write a program that takes in user input from keyboard, stores it in a 2D array, and prints it in revers order. So, if a user typed in:
Line 1
Line 2
The output would be:
Line 2
Line 1
However, I'm stuck on a break condition in my if statement inside the first for loop. Even though I type in "STOP" the program still waits for input. I assume the problem might be due to strcmp function because when I print out the value returned from the function, I'm not getting zero even though my input was "STOP".
#include <stdio.h>
#include <string.h>
int main(){
int i, words = 500, characters = 100, arraylen;
char array[words][characters];
arraylen = sizeof(array)/sizeof(array[0][0]);
printf("Enter lines of words( type \"STOP\" to quit):\n");
for(i = 0; i < arraylen; i++){
fgets(array[i], 100, stdin);
//printf("Value at index %d is %s", i, array[i]);
//printf("Value of strcmp: %d\n", strcmp(array[i], "STOP"));
if(strcmp(array[i], "STOP") == 0){
//if(fgets(array[i], 500, stdin) == "STOP")
break;
}
}
printf("\n");
for(i = arraylen - 1; i >= 0; i--){
printf("%s", array[i]);
}
printf("\n");
return 0;
}
The maximum length of array is really just the value of words.
You also need to need to keep track of how many entries you've added so that you do not run out of space, and so that you can know which position to start printing from, afterwards. As is, you are attempting to print from the very end of the array, from memory that may not have been initialized.
fgets places the newline character ('\n'), if read, in the buffer. You'll either need to remove it, or use strncmp to limit your comparison to the length of your sentinel string.
if (strncmp(buffer, "STOP", 4)) {
/* .. */
}
fgets can also fail, returning NULL to signal this. You need to check its return value in some way, and act appropriately.
An example program:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 500
#define STR_LEN 100
int main(void) {
char strings[MAX_LEN][STR_LEN];
size_t i = 0;
printf("Enter lines of words( type \"STOP\" to quit):\n");
while (i < MAX_LEN && fgets(strings[i], STR_LEN, stdin)) {
strings[i][strcspn(strings[i], "\n")] = '\0';
if (strcmp(strings[i], "STOP") == 0)
break;
i++;
}
while (i--)
printf("%s\n", strings[i]);
}
I have a string in C named buff. It is defined as char *buf = malloc(size);. I'm new to C but think this means that the values of the bytes of data allocated is stored in buf. All code is below
When I run sizeof(buf) it gives a size of 8 despite it clearly being full of more than 8 characters. I also have problems with taking the returned pointer and putting it through strlen which gives a value double what I expect.
This is a function to create an array of characaters read from a file.
The comments below used an example file of input.txt with contents ()()(()()(
const char* readFile()
{
FILE* fp;
int c;
int nch = 0;
int size = 100;
fp = fopen("./input.txt","r");
//allocates a block of 100 bytes and sets buf as the values associated with those values
char *buf = malloc(size);
if(buf == NULL)
{
fprintf(stderr, "out of memory\n");
return NULL;
}
while((c = fgetc(fp)) != EOF) //sets c to the next character of fp and checks it isn't the end
{
if(nch >= size-1) //size-1 as need an extra character for '\0'
{
/* time to make it bigger */
//printf("size: %d \n",size);
size += 50;
buf = realloc(buf, size);
//size_t n = arraySize(buf);
//printf("buf is %zu chars long \n",n);
if(buf == NULL)
{
fprintf(stderr, "out of memory\n");
return NULL;
}
}
buf[nch++] = c; //steps nch and stores c
}
buf[nch++] = '\0';
printf("size: %d\n",size); //output 100
printf("nch: %d\n",nch); //output 11
buf = realloc(buf, nch); //sets the buf to the size it actually needs
printf("buf is %d long\n",sizeof(buf)); //outputs sizeof(buf) as 8.
printf("buf[0] is %d long\n",sizeof(buf[0])); //outputs sizeof(buf[0]) as 1.
printf("\"%s\"\n", buf); //shows it reads the file properly. outputs "0123456789"
return buf;
}
int main(){
const char *fileContents = readFile(); //defines it as the address of the first character
printf("\"%s\"\n", fileContents); //outputs the file contents correctly
int count = 0;
printf("strlen: %d\n",strlen(fileContents)); //outputs 10
int i, lenStr = strlen(fileContents);
for(i = 0; i < lenStr; i++){
char c = *(fileContents+i); //sets character at position i to c
printf("character: %c i: %d\n",c,i); //outputs expected value
switch(c){ //this works sort of and correctly identifies values
case '(':
printf("increasing count\n");
count++;
break;
case ')':
printf("decreasing count\n");
count--;
break;
default:
printf("things are going wrong \n");
break;
}
fileContents++;
}
printf("go up %d floors",count);
getchar();
return 0;
}
output of for loop with select statment
character: ( i: 0
increasing count
character: ( i: 1
increasing count
character: ( i: 2
increasing count
character: ) i: 3
decreasing count
character: ) i: 4
decreasing count
character: i: 5
things are going wrong
character: i: 6
things are going wrong
character: i: 7
things are going wrong
character: e i: 8
things are going wrong
character: s i: 9
things are going wrong
For some reason the output is in the wrong order before it starts breaking.
It feels like the problem is I don't fully understand pointers. I'm just not sure how I am misunderstanding them.
The main problem is that you are doing fileContents++;. This adds one to the pointer fileContents, sliding the place to view.
You should remove this so that the characters will be processed one-by-one thanks to i++ in the for loop.
Another problem is that you are invoking undefined behavior by passing data having wrong type to printf. sizeof operator and strlen returns size_t, but %d expects int. The correct format specifier to print size_t is %zu.
When I print 8 or more characters, symbols always print after the 8th character. Does anyone know what is wrong with the code and how can I fix this?
I've tried with different numbers of characters and it always happens when is more than 8 or 8.
#include <stdio.h>
int main() {
char ch = 0;
char temp[100];
int i = 0;
while (scanf("%c", &ch) == 1) {
if (ch != '\n') {
temp[i] = ch;
printf("%s", temp);
i++;
}
}
return 0;
}
My expected result is
1 12 123 123412345123456123456712345678
My actual output is
1 12 123 123412345123456123456712345678xxx
the x represent the symbols
The reason you get funny characters in the output is the temp array is not a proper C string because it is uninitialized so there is not necessarily a null byte '\0' after the ith entry set with temp[i] = ch;.
There are different ways to fix this problem:
you can initialize temp this way: char temp[100] = { 0 };
you can set the byte at temp[i+1] to '\0' in the loop.
Note also that the expected output is not 1 12 123 123412345123456123456712345678, but 112123123412345123456123456712345678 because you do not output a separator between the strings. It would be less confusing to output the strings on separate lines.
Finally scanf() will not return until the user has typed a newline because of buffering performed by the terminal driver and the standard input stream.
Here is a modified version:
#include <stdio.h>
int main() {
char ch;
char temp[100];
size_t i = 0;
while (scanf("%c", &ch) == 1 && i + 2 < sizeof(temp)) {
if (ch != '\n') {
temp[i] = ch;
temp[i + 1] = '\0';
printf("%s", temp);
i++;
}
}
return 0;
}
#chqrlie well explained and offered 2 alternatives.
3rd alternative: change format
printf("%s\n", temp) expects temp to be a string. In C, a string has a null character, else it is not a string.
Code failed to ensure a '\0' in temp[]. The result is undefined behavior (UB).
Code could use a precision to limit the number of characters printed with "%s".
// printf("%s", temp);
printf("%.*s", (int)i, temp);
"%.*s", (int)i, temp will print up to i characters or up to '\0' - which ever comes first. i is cast as (int) because printf expects an int for the precision given as an extra argument as specified by the .* before the s.
int main(void) {
char temp[100];
size_t i = 0;
while (i < sizeof temp && scanf("%c", &temp[i]) == 1 && temp[i] != '\n') {
i++;
}
printf("<%.*s>\n", (int)i, temp);
return 0;
}
This question already has answers here:
How do I check if a number is a palindrome?
(53 answers)
Closed 5 years ago.
I am trying to check if an input number is a palindrome. I am doing it through strings rather than ints. So, I am taking in a string and reversing it into another string. However, when I use the string compare function it does not give me 0, stating that the strings are not the same. Even when I put in for example "1001", both the input and reverse strings displays 1001. I have figured it out with other methods but am trying to understand what is wrong with this one in specific.
#include <stdio.h>
#include <string.h>
int main(void)
{
char input[100];
char reverse[100];
int numLen = 0;
printf("Enter a number\n");
fgets(input, 100, stdin);
printf("The number is: %s\n", input);
numLen = strlen(input) - 1;
printf("Length of string is: %d\n", numLen);
for (int i = 0; i < numLen; i++)
{
reverse[i] = input[numLen - 1 - i];
if (i == numLen - 1)
{
reverse[i + 1] = '\0';
}
}
printf("The reverse number is: %s\n", reverse);
printf("The original number is: %s\n", input);
int result = strcmp(input, reverse);
printf("Result of strcmp gives us: %d\n", result);
if (strcmp(input, reverse) == 0)
{
printf("These numbers are palindromes\n");
}
else
{
printf("These numbers are not palindromes\n");
}
return 0;
}
The problem is you are not handling the strings properly. You should overwrite the '\n' with \0.
...
char input[100];
char reverse[100];
int numLen = 0;
printf("Enter a number\n");
fgets(input, 100, stdin);
printf("The number is: %s\n", input);
input[strcspn(input,"\n")]='\0'; // getting the length of the
// string without `\n`
// and overwriting with `\0`
numLen = strlen(input) ; // now you don't need to put the -1
printf("Length of string is: %d\n", numLen);
for (int i = 0; i < numLen; i++)
{
....
Apart from these two changes everything else remains the same. You were reversing it all right. And then you used strcmp right way. But the extra \n is removed in the code I have shown.
(still) Why it works?
Now to give you a better idea. You formed the reversed string alright. But the original string has \n within itself.
printf("The reverse number is: (%s)\n", reverse);
printf("The original number is: (%s)\n", input);
In the previous program you just do write these two lines. You will understand where you went wrong.
On giving input 1001Enter it gives this output.
The reverse number is: (1001)
The original number is: (1001
)
What is strcspn doing?
I have using strcspn function got the length without \n and overwriting it with \0.
0 1 2 3 4 5 --> indices
1 0 0 1 \n \0 --> strcspn(input,"\n") returns 4.
1 0 0 1 \0 \0 --> input[strcspn(input,"\n")]='\0'
You can do simply like this without the copying and everything.
Without extra memory - in place palindrome checking
bool checkPal(const char *s){
for(int i = 0, j= strlen(s)-1; i< strlen(s) && j>=0 ; i++)
if(s[i] != s[j])
return false;
return true;
}
int main(void)
{
char input[100];
char reverse[100];
printf("Enter a number\n");
if( fgets(input, 100, stdin) )
printf("The number is: %s\n", input);
input[strcspn(input,"\n")]='\0';
int numLen = strlen(input) ;
printf("Length of string is: %d \n", numLen);
printf("These numbers are %spalindromes\n", checkPal(input)?"not ":"");
return 0;
}
A more succinct way to write the checkPal() would be,
bool checkPal(const char *first){
const char *last = first + strlen(first);
while (first < last) {
if (*first++ != *--last) {
return false;
}
}
return true;
}
last points to the \0 character. Subtraction is necessary before we start doing comparison. To get a clear idea of what happens you have to know the precedence and few rules.
The first<last part is obvious. We are comparing till we reach a point where we first > last (For even length strings) or first = last (for odd length strings).
The if is a bit tricky. *first++ there are two operators involved. * (indirection) and ++(post increment).
And precedence of ++ is higher than de-reference *.
So *first++ will be - first is incremented. Then you might think that we are missing one character very first time but that's not the case. Value of a postfix expression is the value before we do first++. So now you have the first character.
Same way *--last will have the same effect except the value of the prefix expression is the value after the operation. So you are considering the last character.
If they matches we continue. first and last already contain the modified value. We repeat the same logic for rest of the characters in the smaller sub-string.
If a mismatch occurs then we return immediately. (Because it's not a palindrome).
Sorry, my bad. Try this:
#include <stdio.h>
#include <string.h>
// A function to check if a string str is palindrome
void isPalindrome(char str[])
{
// Start from leftmost and rightmost corners of str
int l = 0;
int h = strlen(str) - 1;
// Keep comparing characters while they are same
while (h > l)
{
if (str[l++] != str[h--])
{
printf("%s is Not Palindromen", str);
return;
}
}
printf("%s is palindromen", str);
}
// Driver program to test above function
int main()
{
isPalindrome("abba");
isPalindrome("abbccbba");
isPalindrome("geeks");
return 0;
}
Does this one work?
A variant, recursive version that has no more that the string as argument (or a copy of the original string)
int pal(char *s) {
int n = strlen(s);
if (n <= 1) return 1;
if (s[0] != s[n-1]) return 0;
s[n-1] = '\0';
return pal(++s);
}
return 0: not a palindrome, 1: is a palindrome
Note the string is altered, so you can call it this way if it's a problem (or if the string is created in a static area)
char *copy = malloc(strlen(string)+1); // string is original string
strcpy(copy, string);
int ispal = pal( copy );
printf("Is %s a palindrome\n", ispal ? "":"not");
i have a file like that :
1 100
2 200
3 300
4 400
1
i want to save it as a matrix and i want to save NULL if there is no second number !
i tried to write the program but it does not work correctly !
#include<stdio.h>
int main() {
int k=0 ,i,j , arr[100][100];
FILE *in= fopen("file.txt","r");
char line[1000];
while(fgets(line,1000,in) !=NULL) k++;
fgets(line,1000,in);
for (i=0;i<k;i++){
for (j=0;j<2;j++){
int tmp ;
fscanf(in ,"%d", &tmp) ;
arr[i][j] = tmp ;
}
}
fclose(in);
return 0; }
Two major problems:
The first is that the first loop will read all lines, even the one with the single number on the line. That means the lonely fgets call will not do anything, and more importantly that the value of k will be wrong.
The second problem is that once you read all data from the file, you don't go back to the beginning of the file, instead you continue to try and read from beyond the end of the file.
The first problem can be solve by skipping the second fgets call, and decreasing k by one.
The second problem can be solved by calling rewind after you counted the number of lines.
Also when you actually read the numbers, you don't need the inner loop, just do e.g.
scanf("%d %d", &arr[i][0], &arr[i][1]);
Actually, you don't need the first line-counting loop at all, you can do it all in a single loop, by using fgets and sscanf and then checking the return value of sscanf. So your program could look something like
#include <stdio.h>
int main(void)
{
int values[100][2];
FILE *input = fopen("file.txt", "r");
size_t entries = 0;
if (input != NULL)
{
char buffer[40];
while (fgets(buffer, sizeof(buffer), input) != NULL && entries < 100)
{
int res = sscanf(buffer, "%d %d", &values[entries][0], &values[entries][1]);
if (res <= 1 || res == EOF)
{
// Read the last line with only one number, or an error happened
values[entries][0] = 0;
values[entries][1] = 0;
break;
}
++entries;
}
if (ferror(input))
{
printf("Error reading file\n");
}
fclose(input);
}
// All done, the number of "records" or "entries" is in the variable entries
// Example code: print the values
for (size_t i = 0; i < entries; ++i)
printf("Line %d: %d %d\n", i + 1, values[i][0], values[i][1]);
return 0;
}