So I'm trying to determine the longest line for a school assignment. Here is the code I think is of question. I don't understand why the "longest_line" prints fine in the while loop, but won't print outside the loop.
int main() {
int ch;
char line[MAXLINE] = { '\n' }; /* current input line */
char longest_line[MAXLINE] = { '\n' }; /* copy of longest line */
while ((ch = readline(line, MAXLINE)) != EOF) {
if (longest(line, longest_line))
copy(longest_line, line);
printf("Read Line: %s\n", line);
printf("Long Line: %s\n", longest_line);
}
printf("Print Long Line: %s\n", longest_line);
Here is the output:
calc L
copy
Read Line: sdafasdfsadfsadfs
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sadfs
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sdfasdfsafd
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sadfsdf
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sadfs
Long Line: sdafasdfsadfsadfs
calc L
Read Line:
Long Line: sdafasdfsadfsadfs
calc L
Read Line: sfsafsdfsf
Long Line: sdafasdfsadfsadfs
Print Long Line:
It's like the longest_line gets erased after the loop, which doesn't make sense to me. Sorry I'm a newb. Thanks to the guy who knows the technical reason behind this anomaly.
Here is my entire program if you wish to run it: (I fixed the variables)
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#define MAXLINE 80 /* maximum input line size */
/* function declarations */
int readline( char line[], int max );
void copy( char to[], char from[] );
bool longest( char read_line[], char previous_line[] );
/* print longest input line */
int main() {
int ch;
char line[MAXLINE] = { '\n' }; /* current input line */
char longest_line[MAXLINE] = { '\n' }; /* copy of longest line */
while ((ch = readline(line, MAXLINE)) != EOF) {
if (longest(line, longest_line))
copy(longest_line, line);
printf("Read Line: %s\n", line);
printf("Long Line: %s\n", longest_line);
}
printf("Print Long Line: %s\n", longest_line);
return 0;
}
/* readline: read a line into s, return length */
int readline(char s[], int lim) {
int i = 0; // the current index
char c; // the current char
c = getchar();
while (c != '\n' && i < lim) {
s[i] = c;
i++;
c = getchar();
}
s[i] = '\0'; // final charachter of string
return c;
}
/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[]) {
int i;
for (i = 0; to[i] = from[i]; ++i);
printf("copy\n");
}
/* longest: Which line is the longest */
bool longest( char read_line[], char previous_line[] ) {
printf("calc L\n");
char ch;
int size_read = 0;
int size_previous = 0;
// determine length of read line
ch = read_line[size_read];
while (ch != '\0') {
ch = read_line[size_read];
++size_read;
}
// determine length of previous line
ch = previous_line[size_previous];
while (ch != '\0') {
ch = previous_line[size_previous];
++size_previous;
}
// determine longest line
if (size_read > size_previous)
return true;
else
return false;
}
I won't give the details away, but there are several places in the code where you fail to initialize variables, leading to undefined behaviour.
Related
i have a file (for example lorem.txt)
so now i have two task ,
was to read file and remove space and lines.
to determine the two letter combination that occurs most often in my file.
i have done the first part. can anyone tell me what can i do to 2. part? I tried various solutions, but was unable to do it. Let me know, if I can provide anything else.
#include <stdio.h>
#include <stdlib.h> // For exit()
FILE* pInputFile;
int chr = 0;
int main()
{
FILE* fptr;
char c;
char filename[] = "Lorem.txt";
char *str, *strblank;
// char str[469], strblank[469];
int i = 0;
//int x=500;
errno_t err;
if ((err = fopen_s(&pInputFile, "Lorem.txt", "r")) == 0)
{
size_t pos = ftell(pInputFile); // Current position
fseek(pInputFile, 0, SEEK_END); // Go to end
size_t length = ftell(pInputFile); // read the position which is the size
fseek(pInputFile, pos, SEEK_SET); // restore original position
//x = length;
//char str[x], strblank[x];
printf("%d", length);
str = malloc(length * sizeof(char));
strblank = malloc(length * sizeof(char));
// file exists: don't read a char before the loop or
// it will be lost
while ((chr = getc(pInputFile)) != EOF)
{
//printf("%c", chr); //This line prints the file lines.
str[i] = chr;
i++;
}
i= 0;
printf("%s", str);
removespace(str, strblank);
printf("%s", strblank);
fclose(pInputFile);
}
else
{
fprintf(stderr, "Cannot open file, error %d\n", err);
// handle the error further if needed
}
return 0;
}
int removespace(char aj[500],char mj[500])
{
//char mj[500];
int i = 0, j = 0, len;
//printf("\n\nEnter the string: ");
//gets(aj);
len = strlen(aj); // len stores the length of the input string
while (aj[i] != '\0') // till string doesn't terminate
{
if (aj[i] != ' ' && aj[i] != '\n') // if the char is not a white space
{
/*
incrementing index j only when
the char is not space
*/
mj[j++] = aj[i];
}
/*
i is the index of the actual string and
is incremented irrespective of the spaces
*/
i++;
}
mj[j] = '\0';
// printf("\n\nThe string after removing all the spaces is: ");
return 0;
}
I want to receive the number of lines of input from the user then read and save the lines of unknown lengths in an array.
I know that the way I am saving the lines is wrong but I don't know how to correct it.
int nos; // number of strings
scanf_s("%d", &nos);
char** strs = malloc(nos * sizeof(char*)); // array of strings
for (int i = 0; i < nos; i++) // receiving strings
{
scanf_s("%s", (strs+i));
}
You're close, but you're forgetting to allocate memory for the string. If you're working with POSIX-compliant systems (i.e. pretty much everything except Windows) then use the %ms scanf() format specifier to allocate the buffer for the string as you're reading it (note that this stops after whitespace):
scanf("%ms", &strs[i]);
For Windows, implement a gets()-like function:
#include <stdlib.h>
#include <stdio.h>
int msgets(char **str)
{
int ch = 0;
size_t len = 0;
while(ch != '\n')
{
len++;
*str = realloc(*str, len);
ch = getchar();
(*str)[len-1] = ch;
}
(*str)[--len] = 0;
return len;
}
Here's how to use it in replacement of the scanf() line:
msgets(&strs[i]);
Other than that, your code looks fine.
Here's an almost complete example with my code included:
#include <stdlib.h>
#include <stdio.h>
int msgets(char **str)
{
int ch = 0;
size_t len = 0;
while(ch != '\n')
{
len++;
*str = realloc(*str, len);
ch = getchar();
(*str)[len-1] = ch;
}
(*str)[--len] = 0;
return len;
}
int main(void)
{
int nos; // number of strings
scanf("%d ", &nos);
char** strs = malloc(nos * sizeof(char*)); // array of strings
for (int i = 0; i < nos; i++) // receiving strings
{
msgets(&strs[i]);
}
/* Do something with strs[] here */
return 0;
}
if you read carefully this answerHow can I read an input string of unknown length? , and modify your code it should be something like this.
I also add a print for loop to see the results of this code
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE* fp, size_t size){
char *str=NULL;
int ch;
size_t len = 0;
str = realloc(str, sizeof(char)*size);
if(!str){
printf("[DEBUG]\n");
return str;
}
while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
str[len++]='\0';
return realloc(str, sizeof(char)*len);
}
void empty_stdin (void) /* simple helper-function to empty stdin */
{
char c;
while ((c = getchar()) != '\n' && c != EOF);
return;
}
int main(void){
int nos,i; /*number of strings*/
scanf("%d", &nos);
empty_stdin();
char ** strs = malloc(nos * sizeof(char*)); /*array of strings*/
for (i = 0; i < nos; i++) {/*receiving strings*/
*(strs+i) = inputString(stdin,1);
}
for(i=0;i<nos;i++){
printf("%s\n",*(strs+i));
}
return 0;
}
input:
3
123456789
foo
hello world
output:
123456789
foo
hello world
So I am trying to read input from a text file and print the exact same thing I read in C.So this below is the input followed by enter:
input: Hi
output: Hi
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE *fp, size_t size) {
//The size is extended by the input with the value of the provisional
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char) * size); //size is start size
if (!str)
return str;
while (EOF != (ch = fgetc(fp)) && ch != '\n') {
str[len++] = ch;
if (len == size) {
str = realloc(str, sizeof(char) * (size += 16));
if (!str)
return str;
}
}
str[len++] = '\0';
return realloc(str, sizeof(char) * len);
}
int main(void) {
char *m;
// printf("input string : ");
m = inputString(stdin, 10);
printf("%s\n", m);
free(m);
return 0;
}
For this input:
Hi, this is the first line
This is the second line
This is the third line \n
This is the output I expected:
Hi, this is the first line
This is the second line
This is the third line \n
This is what I got:
Hi, this is the first line
It makes sense that the code is printing only the first line, but since the condition in the guard will no longer be true after hitting the new line, but I don't know how to structure my code so it reads line by line and prints them respectively.
If you want the code to read each line, remove && ch != '\n' from the condition of the while loop.
Also, the code is reading from stdin instead of a file. Use fopen to read from a file, i.e. m = inputString(fopen("filename.txt", "r"), 512).
Try this,
#include<stdio.h>
void main(int argc, char **argv)
{
int cnt=0;
char buf[1024];
FILE *fptr=stdin;
printf("Input: \n");
char ch=fgetc(fptr);
buf[cnt++]=ch;
while(ch!='$')
{
buf[cnt++]=ch;
ch=fgetc(fptr);
}
buf[cnt++]='$';
buf[cnt]='\0';
printf("Output:\n");
fputs(buf,stdout);
fclose(fptr);
}
I have put '$' as the delimiter.
I have used an extra buffer as newline is bound to EOF for stdin. So if I print out the character immediately it comes out of loop.
All you need is repeat the process as long as you can read lines:
int main(void) {
char *m;
// printf("input strings: ");
while ((m = inputString(stdin, 10)) != NULL) {
printf("%s\n", m);
free(m);
}
return 0;
}
For this to work correctly, you must return NULL at end of file:
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE *fp, size_t size) {
//The size is extended by the input with the value of the provisional
int ch;
size_t len = 0;
char *str = malloc(size);
if (str == NULL)
return NULL;
while ((ch = fgetc(fp)) != EOF && c != '\n') {
if (len + 2 > size) {
char *new_str = realloc(str, size += 16);
if (!new_str) {
free(str);
return NULL;
str = new_str;
}
str[len++] = ch;
}
if (c == EOF && len == 0) {
/* at end of file */
free(str);
return NULL;
}
str[len++] = '\0';
return realloc(str, len);
}
Instead of:
while(EOF!=(ch=fgetc(fp))&& ch != '\n' ){
// stuff
}
you could do:
while(EOF!=(ch=fgetc(fp))){
// stuff
if (ch == '\n') break;
}
Now you have consumed the newline.
I had to rewrite two functions as per two exercises in a book I'm working from. One that simply reads a line of characters, readLine and another that compared two character strings and returned either 1 or 0 based on whether they match, 'equalStrings`.
The point of the exercise was to rewrite the functions so they used pointers, as opposed to arrays.
I've been struggling with prior exercises and was surprised how quickly I was able to do this so I'm concerned I'm missing something important.
Both programs compile and run as hoped though.
This is the original readLine function:
#include <stdio.h>
void readLine(char buffer[]);
int main(void)
{
int i;
char line[81];
for(i = 0; i < 3; i++)
{
readLine(line);
printf("%s\n\n", line);
}
return 0;
}
void readLine(char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
My edited with pointers:
#include <stdio.h>
void readLine(char *buffer);
int main(void)
{
int i;
char line[81];
char *pointer;
pointer = line;
for(i = 0; i < 3; i++)
{
readLine(pointer);
printf("%s\n\n", line);
}
return 0;
}
void readLine(char *buffer)
{
char character;
int i;
i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
Here is the original equalString function:
#include <stdio.h>
#include <stdbool.h>
bool equalStrings(const char s1[], const char s2[]);
int main(void)
{
const char stra[] = "string compare test";
const char strb[] = "string";
printf("%i\n", equalStrings(stra, strb));
printf("%i\n", equalStrings(stra, stra));
printf("%i\n", equalStrings(strb, "string"));
return 0;
}
bool equalStrings(const char s1[], const char s2[])
{
int i = 0;
bool areEqual;
while(s1[i] == s2[i] && s1[i] != '\0'){
i++;
if(s1[i] == '\0' && s2[i] == '\0')
areEqual = true;
else
areEqual = false;
}
return areEqual;
}
and the rewritten with pointers:
#include <stdio.h>
#include <stdbool.h>
bool equalStrings(const char *pointera, const char *pointerb);
int main(void)
{
const char stra[] = "string compare test";
const char strb[] = "string";
const char *pointera;
const char *pointerb;
pointera = stra;
pointerb = strb;
printf("%i\n", equalStrings(pointera, pointerb));
printf("%i\n", equalStrings(pointerb, pointerb));
printf("%i\n", equalStrings(strb, "string"));
return 0;
}
bool equalStrings(const char *pointera, const char *pointerb)
{
int i = 0;
bool areEqual;
while(pointera[i] == pointerb[i] && pointera[i] != '\0'){
i++;
if(pointera[i] == '\0' && pointerb[i] == '\0')
areEqual = true;
else
areEqual = false;
}
return areEqual;
}
Is there anything glaring out that needs to be changed?
Thank you.
There are (3) conditions you need to protect against in your readline function. (1) you must protect against writing beyond the end of your array. Utilizing a simple counter to keep track of the number of characters added will suffice. You can express this limit in your read loop. Your array size is 81 (which will hold a string of 80 characters +1 for the nul-terminating character. Assuming you create a #define MAXC 81 for use in your code, your first condition could be written as:
void readline (char *buffer)
{
int i = 0, c;
while (i + 1 < MAXC && ...
(2) the second condition you want to protect against is reaching a '\n' newline character. The second condition for your read loop could be written as:
while (i + 1 < MAXC && (c = getchar()) != '\n' && ...
(3) the third condition you must protect against is encountering EOF with a line before a newline character is reached (many editors produce files with non-POSIX line-endings). With the final condition, your complete set of test conditions could look like the following:
while (i + 1 < MAXC && (c = getchar()) != '\n' && c != EOF)
(and that is why c must be signed (and should be a signed int), because EOF is generally -1)
Putting that together, with what it appears was intended in rewriting the function from using array-index notation to using pointer notation, you could do something like the following:
void readline (char *buffer)
{
int i = 0, c;
while (i + 1 < MAXC && (c = getchar()) != '\n' && c != EOF) {
*buffer++ = c;
i++;
}
*buffer = 0;
if (i + 1 == MAXC && *(buffer - 1) != '\n')
fprintf (stderr, "warning: line truncation occurred.\n");
}
You should also check, as shown above, whether you read all the characters in the line, or whether a short-read occurred (meaning after reading 80 allowable characters, there were still more characters in the line to be read, but to prevent writing beyond the end of your array, and leaving room for the terminating nul, you stopped reading before your reached the newline). You are free to handle it as you like, but be aware -- those characters still exist in the input buffer (stdin here) and will be the very next characters read on your next call to getchar(). So you may want a way to tell if that occurred.
Putting the function together in a short example with a helpful input file will help explain.
#include <stdio.h>
#define MAXC 81
void readline(char *buffer);
int main(void) {
int i;
char line[MAXC] = "", *pointer = line;
for(i = 0; i < 3; i++) {
readline (pointer);
printf ("%s\n\n", line);
}
return 0;
}
void readline (char *buffer)
{
int i = 0, c;
while (i + 1 < MAXC && (c = getchar()) != '\n' && c != EOF) {
*buffer++ = c;
i++;
}
*buffer = 0;
if (i + 1 == MAXC && *(buffer - 1) != '\n')
fprintf (stderr, "warning: line truncation occurred.\n");
}
How will your function behave if given a 90 character line to read?
Input File
Two lines with 90 characters each.
$cat dat/90.txt
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Example Use/Output
Note what has occurred. On the first read attempt, 80 character were read, and a short read occurred. You were warned of that fact. The second read, read the reamining 10 characters in the first line (chars 81-90). The third, and final, read, again reads the first 80 chars of the second line and the code terminates.
$ ./bin/getchar_ptr <dat/90.txt
warning: line truncation occurred.
12345678901234567890123456789012345678901234567890123456789012345678901234567890
1234567890
warning: line truncation occurred.
12345678901234567890123456789012345678901234567890123456789012345678901234567890
I'll let you look this over and incorporate any of the suggestions you find helpul in the rest of your code. Let me know if you have any questions. Make sure you fully undetstand what is being passed as buffer in void readline (char *buffer) (copy as opposed to original) as basic pointer understandin has implications throughout C.
New to programming, working through K&R. After inputting using the stdin, I press ^D to write EOF (i'm using linux), and... nothing happens. I'm still able to write to the console, and able to ^Z to suspend, but not able to use ^D. I expected my code to read the input and print all the lines longer than the requirement, and as I can't produce any output, I'm not sure where to begin diagnosing my problem.
/*
Exercise 1-17 in K&R: page 31 in book
Write a program to print all input lines that are longer than 80 characters
*/
# include <stdio.h>
# define MIN_LINE 5 /*change to 80 for final*/
# define MAX_LINE 20 /*change for final*/
int getline(char line[], int max);
void copy(char to[], char from[], int position);
int main()
{
char line[MAX_LINE];
int len = 0;
char print_register[MAX_LINE];
int reg_index = 0;
/*read length of line*/
while ((len = getline(line, MAX_LINE)) != EOF)
{
/*if len > 80; append to print-array*/
if (len > MIN_LINE)
{
copy(print_register, line, reg_index);
}
}
/*print the print-array*/
printf("%s", print_register);
return 0;
}
int getline( char line[], int max)
{
int i;
int c;
for (i = 0; (c = getchar()) != EOF && c != '\n' && i <= max; i++)
{
line[i] = c;
}
/* handle '\n' and EOF */
if (c == '\n')
{
line[i] = c;
i++;
}
line[i] = '\0';
return i;
}
void copy(char to[], char from[], int position)
{
int i;
while ((to[position] = from[i]) != '\0')
{
i++;
position++;
}
}
Your getline() function returns the length and not EOF. Hence the following statement should be replaced:
while ((len = getline(line, MAX_LINE)) != EOF)
The EOF should be replaced with 0:
while ((len = getline(line, MAX_LINE)) != 0)
you need to initialize the "i" value in copy function, if not it may take some unexpected value and getline() output is returning number of characters not EOF so you need to change while loop condition also.
Changes:
Original : while ((len = getline(line, MAX_LINE)) != EOF)
changed : while ((len = getline(line, MAX_LINE)) != 0)
void copy(char to[], char from[], int position)
{
// int i; Original
int i =0;
while ((to[position] = from[i]) != '\0')
{
i++;
position++;
}
}
if you initialize i=0 in copy function, you will get output.