How to count spaces and pass characters or newline? - c

I was writing a tool that replaces enough spaces with tab,
but it counts more spaces than expected.
Algorithm should count spaces until seeing character or
newline, if there is a character or newline, it passes to next
element of string; but unfortunately continues to count spaces instead
of passing newline or character.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define BUFFER_SIZE 100
int set_tab_init_arg(char *filename, int space_size)
{
struct stat filest;
FILE *fp = fopen(filename, "r+");
int fd = fileno(fp);
int line = 0, space = 0, var = 0, offset = 0;
if (fstat(fd, &filest) < 0)
return -1;
char *filecontent = (char*)malloc(filest.st_size);
char buff[BUFFER_SIZE];
if (fp == NULL) {
fprintf(stderr, "cyntax: invalid file pointer!\n");
return -1;
}
while (fgets(buff, BUFFER_SIZE, fp) != NULL)
strcat(filecontent, buff);
char *tmpcontent, *willbewrited = filecontent;
for (int x = 0; x < strlen(filecontent); x++) {
if (filecontent[x] == 32) {
printf("space\n");
space++;
}
else if (filecontent[x++] == 10) {
line++;
printf("newline: %d\n", line);
space = 0;
}
else {
printf("char\n");
x++;
var++;
}
if (space == space_size) {
replace_spaces_to_tab();
printf("space = space_size\n");
}
filecontent++, offset++;
}
}
here is file I tested on:
a
b
c
d
e f g
c h e
p ğ a
and debug result is here (stdout):
space
newline: 1
newline: 2
newline: 3
newline: 4
space
space
space = space_size
newline: 5
space
space
space = space_size
newline: 6
space
char
I executed with parameters:
./cyntax try -t 2
Note-1: try is file and -t 2 gets space size for converting enough spaces to tab.
Note-2: I used printf() function for debugging.

I think your problems were created by:
incrementing x additionally in the for loop x++; ( I believe this was already fixed in the comments)
incrementing the filecontent pointer at the end of your for loop filecontent++;
I code on linux. That's why I had to change your line break detection slightly. (Do line endings differ between Windows and Linux?). not relevant to your problem though...
My Solution
I markes my changes with CHANGE::
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define BUFFER_SIZE 100
int set_tab_init_arg(char *filename, int space_size)
{
struct stat filest;
FILE *fp = fopen(filename, "r+");
int fd = fileno(fp);
int line = 0, space = 0, var = 0, offset = 0;
if (fstat(fd, &filest) < 0)
return -1;
char *filecontent = (char*)malloc(filest.st_size);
char buff[BUFFER_SIZE];
if (fp == NULL) {
fprintf(stderr, "cyntax: invalid file pointer!\n");
return -1;
}
while (fgets(buff, BUFFER_SIZE, fp) != NULL)
strcat(filecontent, buff);
char *tmpcontent, *willbewrited = filecontent;
for (int x = 0; x < strlen(filecontent); x++) {
if (filecontent[x] == 32) {
printf("space\n");
space++;
}
else if (filecontent[x] == 10) { // CHANGE:: on linux. for windows filcontent[x++] is right :)
line++;
printf("newline: %d\n", line);
space = 0;
}
else {
printf("char\n");
//x++; //CHANGE:: removed else you would skip after chars
var++;
space = 0;
}
if (space == space_size) {
// replace_spaces_to_tab(); //CHANGE:: commented just to be able to compile
printf("space = space_size\n");
}
// filecontent++; //CHANGE:: removed else you would skip chars
offset++;
}
}
//CHANGE:: needed a main...
int main(){
set_tab_init_arg("try",2 );
}
compiled with gcc on linux fedora:
gcc -Wall -Wextra -g -o a.out main.c
testfile:
a
b
c
d
e f g
c h e
p ğ a
my output to your testfile:
% ./a.out
space
char
newline: 1
space
char
newline: 2
space
char
newline: 3
space
char
newline: 4
space
char
space
char
space
char
newline: 5
space
char
space
char
space
char
newline: 6
space
char
space
char
char
space
char
newline: 7

Related

pallindrome is not copied to next file but printed on output screen

I have a file named fp1 containing different names, some being palindromes, and have to read all names from fp1 and check if each name is a palindrome or not. If it's a palindrome the I need to print the name to screen and copy it to another file named fp.
Here's my program:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
void main() {
FILE *fp, *fp1;
char m, y[100];
int k = 0, i = 0, t = 1, p = 0;
fp = fopen("C:\\Users\\HP\\Desktop\\New folder\\file 2.txt", "w");
fp1 = fopen("C:\\Users\\HP\\Desktop\\New folder\\file4.txt", "r");
if (fp == NULL) {
printf("error ");
exit(1);
}
if (fp1 == NULL) {
printf("error");
exit(1);
}
k = 0;
m = fgetc(fp1);
while (m != EOF) {
k = 0;
i = 0;
t = 1;
p = 0;
while (m != ' ') {
y[k] = m;
k = k + 1;
m = fgetc(fp1);
}
p = k - 1;
for (i = 0; i <= k - 1; i++) {
if (y[i] != y[p]) t = 0;
p = p - 1;
}
if (t == 1) {
fputs(y, fp);
printf("%s is a pallindrome\n", y);
}
m = fgetc(fp1);
}
fclose(fp);
fclose(fp1);
}
coping pallindrome from one file to next file
You are not null terminating your buffer before attempting to use the contents as a string. After placing the last valid character read by fgetc into the buffer, you must place a null terminating character (\0).
A character buffer without a null terminating byte is not a string. Passing such a buffer to fputs, or the printf specifier %s without a length bound, will invoke Undefined Behaviour.
fgetc returns an int, not a char. On systems where char is unsigned, you will not be able to reliably test against the negative value of EOF.
The inner while loop is not checking for EOF. When the file is exhausted, it will repeatedly assign EOF to the buffer, until the buffer overflows.
To that end, in general, the inner while loop does nothing to prevent a buffer overflow for longer inputs.
In a hosted environment, void main() is never the correct signature for main. Use int main(void) or int main(int argc, char **argv).
Note that fputs does not print a trailing newline. As is, you would fill the output file full of strings with no delineation.
The nested while loops are fairly clumsy, and I would suggest moving your palindrome logic to its own function.
Here is a refactored version of your program. This program discards the tails of overly long words ... but the buffer is reasonably large.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 1024
FILE *open_file_or_die(const char *path, const char *mode)
{
FILE *file = fopen(path, mode);
if (!path) {
perror(path);
exit(EXIT_FAILURE);
}
return file;
}
int is_palindrome(const char *word, size_t len)
{
for (size_t i = 0; i < len / 2; i++)
if (word[i] != word[len - i - 1])
return 0;
return 1;
}
int main(void)
{
/*
FILE *input = open_file_or_die("C:\\Users\\HP\\Desktop\\New folder\\file4.txt", "r");
FILE *output = open_file_or_die("C:\\Users\\HP\\Desktop\\New folder\\file 2.txt", "w");
*/
FILE *input = stdin;
FILE *output = stdout;
char buffer[BUFFER_SIZE];
size_t length = 0;
int ch = 0;
while (EOF != ch) {
ch = fgetc(input);
if (isspace(ch) || EOF == ch) {
buffer[length] = '\0';
if (length && is_palindrome(buffer, length)) {
fputs(buffer, output);
fputc('\n', output);
printf("<%s> is a palindrome.\n", buffer);
}
length = 0;
} else if (length < BUFFER_SIZE - 1)
buffer[length++] = ch;
}
/*
fclose(input);
fclose(output);
*/
}

How do I print specfic parts of a string in a file

I'm writing a program that will read from /etc/passwd and output the username and shell.
For example, here is the first line:
root:x:0:0:root:/root:/bin/bash
I need to only output the user and the shell. In this instance it would print:
root:/bin/bash
The values are seperated by : so I just need to print the string before the first : and the string after the 6th :. How can I do that?
Here is the code I have so far:
#include <unistd.h>
#include <fcntl.h>
//printf and scanf prototype
int printf(const char *text, ...);
int scanf(const char *format, ...);
int main(void)
{
int fd;
int buff_size = 1;
char buff[512];
int size;
fd = open("/etc/passwd",O_RDONLY);
if (fd < 0)
{
printf("Error opening file \n");
return -1;
}
while ((size = read(fd,buff,1))>0)
{
buff[1] = '\0';
printf("%s",buff);
}
}
So far the code reads from /etc/passwd and prints out the whole file line by line. I need to configure the printf statement to just print the user and shell for each instance.
I just need to print the string before the first : and the string after the 6th :.
Filter the string, put the needed data into an output buffer, and print the output buffer.
Since you already used char buff[512]; as the original data buffer, then just create another buffer for output. i.e. char outbuff[512];
// char buff[512]; assume already defined as that in PO
// char outbuff[512]; assume already defined as that in PO
void customized_print(char* buff, char* outbuff) {
int i = 0, j = 0, cnt = 0;
while (i < 512) { // copy until first ':'
if((outbuff[j++]=buff[i++]) == ':') break;
}
// skip 5 more ':'
while (i < 512 && cnt < 5) {
if(buff[i++] == ':') cnt++;
}
// copy the remains
while (i < 512) {
if( (outbuff[j++]=buff[i++]) == '\0' ) break;
}
printf("%s\n", outbuff);
outbuff[0] = 0; // clean the outbuff
}
Another solution with a demo of full code.
If you do not need to use buff. You can use the following solution.
#include <stdio.h>
void customized_print(char* buff, char* outbuff) {
int cnt = 0;
char* p = outbuff;
while (*buff) { // copy until first ':'
if((*p++=*buff++) == ':') break;
}
// skip 5 more ':'
while (*buff && cnt < 5) {
if(*buff++ == ':') cnt++;
}
// copy the remains
while (*buff) {
if( (*p++=*buff++) == '\0' ) break;
}
printf("%s\n", outbuff);
outbuff[0]=0; // clean the outbuff
}
int main(){
char outbuff[512];
customized_print("root:x:0:0:root:/root:/bin/bash", outbuff);
customized_print("foo:x:0:0:root:/root:/bin/bash", outbuff);
return 0;
}
Compile and run:
gcc -Wall demo.c -o demo.out
./demo.out
Output:
root:/bin/bash
foo:/bin/bashh

How would I create an array of char* after reading an unknown number of strings (each of unknown length) from a file? [duplicate]

This question already has answers here:
How should character arrays be used as strings?
(4 answers)
Closed 12 months ago.
I have a file with an unknown number of strings and each of these strings is of an unknown length.
I would like to make each line of the file its own string in an array of strings.
I tried to use dynamic allocation in a char** array, but I don't think I'm approaching this correctly.
Below is the code I have tried. It's getting stuck in an infinite loop, and I can't figure out why.
(The text file I'm reading from ends with a line break, by the way.)
#include <getopt.h> //for getopts
#include <sys/stat.h> //to do file stat
#include <dirent.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h> //user macros
#include <stdlib.h>
#include <stdbool.h>
#include <libgen.h>
#include <errno.h>
int main(int argc, char *argv[]) {
//storing the filename inside string
char* filename = argv[1];
FILE *fp1 = fopen(filename, "r");
if (fp1 == NULL) {
fprintf(stderr, "Error: Cannot open '%s'. No such file or directory.\n", filename);
return EXIT_FAILURE;
}
/**
* we begin by getting the number of numbers in the file
* the number of numbers = number of lines = number of line breaks
*/
size_t numNumbers = 0;
// while((fscanf(fp1, "%*[^\n]"), fscanf(fp1, "%*c")) != EOF){
// numNumbers = numNumbers + 1;
// }
char c;
while((c = fgetc(fp1)) != EOF){
if(c == '\n'){
numNumbers++;
}
}
fclose(fp1);
FILE *fp2 = fopen(filename, "r");
char** arrayOfStrings = malloc(numNumbers * sizeof(char*));
for(int i = 0; i < numNumbers; i++) {
int len = 0;
if(((c = fgetc(fp1)) != '\n') && (c != EOF)){
len++;
}
arrayOfStrings[i] = malloc(len * sizeof(char));
}
printf("hello1\n");
//for(int i = 0; i < numNumbers; i++){
// fscanf(fp2, "%s", (arrayOfStrings[i]));
//}
fclose(fp2);
// for(int i = 0; i < numNumbers; i++){
// fprintf(stdout, "%s", arrayOfStrings[i]);
// }
return 0;
}
(I'm very new to C, so please go easy on me!)
In C, strings are terminated with a '0' byte, so it looks like your malloc for each string is 1 character too short -- you've only allowed space for the text.
In addition, you mean the count for the size of each line to be a while loop, not an if statement - right now you are counting each line as length "1".
Finally, you are reading off the end of the file in your commented out fscanf code because you haven't closed and reopened it.
Assuming you want to split the input to the strings by the newline character, would you please try:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *filename; // filename to read
char **arrayOfStrings = NULL; // array of strings
char line[BUFSIZ]; // line buffer while reading
char *p; // temporal pointer to the input line
int i, num; // counter for lines
FILE *fp; // file pointer to read
if (argc != 2) {
fprintf(stderr, "usage: %s file.txt\n", argv[0]);
return EXIT_FAILURE;
}
filename = argv[1];
if (NULL == (fp = fopen(filename, "r"))) {
perror(filename);
return EXIT_FAILURE;
}
// read the input file line by line
while (fgets(line, BUFSIZ, fp)) {
if ((p = strrchr(line, '\n'))) *p = '\0'; // remove trailing newline, if any
if ((p = strrchr(line, '\r'))) *p = '\0'; // remove trailing cr character, if any
if (NULL == (arrayOfStrings = realloc(arrayOfStrings, (num + 1) * sizeof(char **)))) {
// enlarge the array according to the line count
perror("realloc");
return EXIT_FAILURE;
}
if (NULL == (arrayOfStrings[num] = malloc(strlen(line) + 1))) {
// memory for the string of the line
perror("malloc");
return EXIT_FAILURE;
}
strcpy(arrayOfStrings[num], line);
num++;
}
// print the strings in the array
for (i = 0; i < num; i++) {
printf("%d %s\n", i, arrayOfStrings[i]);
}
fclose(fp);
return 0;
}
If the input file looks something like:
This
is
the
input.
Then the output will be:
0 This
1 is
2 the
3 input.

Something weird using fgets

If I'm printing the whole string everything looks good, whitespace and indenting looks perfect (I'm loading the source file with this code).
But if I'm trying to print a single character in the buffer I'm getting letters where there are not supposed to be any.
For example, if I print buffer[2] I'm getting letters where it should be whitespace, but if I print the whole string the letters aren't there.
Here is my code that's not working:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char *buffer = (char*) malloc(100*sizeof(char));
FILE *myFile;
myFile = fopen("thisSourceFile.c", "r");
if (!myFile) {
printf("could not open file");
}
else {
while(fgets(buffer,100,myFile)) {
printf("%c \n",buffer[2]);
}
}
fclose(myFile);
free(buffer);
buffer = NULL;
return 0;
}
OUTPUT:
n
n
n
t
h
I
y
f
p
l
w
p
}
r
u
e
As you can se it is printing letters where it should by whitespace. Those letters are not there if I print the whole string.
If you're interested in parsing a source file and processing each character, this might be a solution.
But there are two constants; charsand num_lines_to_read.
M.M mentions in the comments below that isprint() isn't fully portable and comes with some quirks to be careful of.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
const int chars = 100; /* Num chars per line to read */
const int num_lines_to_read = 3; /* Num lines to read */
char *buffer = (char*) malloc(chars*sizeof(char));
int i = 0, j = 0;
FILE *myFile;
myFile = fopen("thisSourceFile.c", "r");
if (myFile == NULL) {
printf("could not open file");
fclose(myFile);
return 1;
}
for(i=0; i<num_lines_to_read; i++)
{
if(fgets(buffer,chars,myFile) != NULL)
{
while(isprint((unsigned char) buffer[j]))
{
printf("%c", (buffer[j]));
j++;
}
j=0;
}
}
fclose(myFile);
free(buffer);
return 0;
}
Example output (itself!):
#include <stdio.h>#include <stdlib.h>#include <ctype.h>

Reading in bytes of a file for printable ASCII characetrs

I have to write a program that takes a file name from the command line.
It then read several bytes from the file, looking for strings of printable characters (ASCII values between 32 and 126 decimal).
Then print out the strings.
A string is a run of at least 4 consecutive printable characters and ends whenever a non-printable character is encountered.
Whenever such a string is found, print it out on a new line.
What I have so far is:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
FILE *fp;
fp = fopen(argv[1], "rb");
char buffer;
while(fp != NULL)
{
fread(&buffer, 1, 1, fp);
}
fclose(fp);
}
What I think this does it take the program from the command line and read in all the bytes of the file 1 by 1 and store them into buffer.
Now I need to check each part of the array and see if each element is between 32 and 136.
If it is, I add those bytes to another array until there is a byte not in this range.
Do this for the entirety of the buffer array.
Is this a code approach and is this right so far?
Change the while loop a bit. What you're checking is whether the file exits or not in a loop which won't fetch the required result you want.
fp is comapared with NULL to find out if the file opening is succesful or not as fopen returns address of the file if it opens a file or NULL saying something went wrong.
if( fp == NULL )
{
perror("Error while opening the file\n");
exit(0);
}
What you want do is following lines:
while( ( ch = fgetc(fp) ) != EOF ) { // reads character by character from the file
if((ch <32) || (ch>136)) // check if it is in range to printed
break;
else
printf("%c",ch); // format whoever you want
}
If I understand you correctly, you want your program to read characters from a file (the file might contain non-printable characters), and check if the character falls in the range of 32 to 126 (printable character). If it is, then add that character to a buffer and read more characters until a non-printable character is found. It should also make sure that the string should have at least 4 characters; string should be printed on a newline.
Here is the code that might help you. It was compiled with gcc, and I hope it works for you too.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *fp;
char buf[100], ch; //the size of the array would vary according to your need
int i=0;
//check for enough arguments
if(argc<2)
{
printf("\nInsufficient Arguments.\n");
printf("\nUsage: PrintChar <file>\n\n");
return 1;
}
//open the file in binary mode and check for exisitence of the file
if((fp = fopen(argv[1], "rb"))== NULL)
{
printf("\nError: Unable to open the file.\n");
return 2;
}
i=0;
while( (ch = fgetc(fp))!=EOF )
{
//check for the range
if(ch>=32 && ch<=126)
{
buf[i] = ch; i++;
//This loop will run till it find a next unprintable character (not between the range of 32 and 126
//we also check for the EOF while reading the characters
while( ( (ch = fgetc(fp))>=32 && ch<=126 ) && ch!=EOF )
{
buf[i] = ch; i++;
}
buf[i] = '\0'; //adding the NULL character
//if the string is at least of 4 letters, print it
if(i>=4)
printf("\n%s", buf);
//reset the counter
i=0;
}
}
fclose(fp);
return 0;
}
File contents - test.txt, that I used:
---------------------------------------------------------------
This is a string
anotherline of text #$%#$%#$% #$% #$%345#$$%&$&##$!##~#######
!∞▬345345µ∞#452353453$%##$%#$%$%%^&%^*4234346443754754451} 
and this is the output of the program:
C:\Users\shine\Documents\MYCPROGS\forStackoverflow>printchar test.txt
This is a string
anotherline of text #$%#$%#$% #$% #$%345#$$%&$&##$!##~#######
345#$%##$%##452353453$%##$%#$%$%%^&%^*4234346443754754451}
345345
-------------------------------------------------------------------
Hope this would be helpful. I made this is a hurry, so please let me know if you find something wrong in it.
Read one character each time, write when we find long enough string or have to:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
size_t min_str_len = 4;
size_t buf_len = 4; /* Must greater than or equal to min_str_len */
char buf[buf_len], ch;
size_t out_len, last_len;
last_len = out_len = 0;
while (fread(&ch, 1, 1, stdin) > 0) {
if (isprint(ch)) {
buf[out_len++] = ch;
if (out_len >= buf_len) {
fwrite(buf, 1, out_len, stdout);
last_len += out_len;
out_len = 0;
}
}
else {
if (out_len + last_len >= min_str_len) {
fwrite(buf, 1, out_len, stdout);
#ifdef NEWLINE
fwrite("\n", 1, 1, stdout);
#endif
last_len = out_len = 0;
}
else {
out_len = 0;
}
}
}
exit(EXIT_SUCCESS);
}
If you want to read more than one byte each time, this "at least 4 consecutive printable characters" will make it a little bit tricky:
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
size_t str_min_len = 4;
size_t buf_len = 1024; /* Must greater than or equal to str_min_len */
char in_buf[buf_len], out_buf[buf_len];
size_t out_len, in_len, last_len;
last_len = out_len = 0;
while ((in_len = fread(in_buf, 1, buf_len, stdin)) > 0) {
assert(out_len == 0);
for (size_t i = 0; i < in_len; i++) {
char ch = in_buf[i];
if (isprint(ch)) {
out_buf[out_len++] = ch;
}
else {
if (out_len + last_len >= str_min_len) {
fwrite(out_buf, 1, out_len, stdout);
#ifdef NEWLINE
/* Write a newline between strings. */
fwrite("\n", 1, 1, stdout);
#endif
last_len = 0;
}
out_len = 0;
}
}
if (0 < out_len && out_len < str_min_len) {
size_t pad_len = str_min_len - out_len;
for (size_t i = 0; i < pad_len; i++) {
char ch;
if (fread(&ch, 1, 1, stdin) < 1) {
exit(EXIT_SUCCESS);
}
else if (isprint(ch)) {
out_buf[out_len++] = ch;
}
else {
break;
}
}
}
if (out_len >= str_min_len) {
fwrite(out_buf, 1, out_len, stdout);
last_len = out_len;
out_len = 0;
}
else {
last_len = out_len = 0;
}
}
exit(EXIT_SUCCESS);
}

Resources