"Overwrite" repeated values in a file (C) [closed] - c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Hello i have a little problem, and i cannot find a solution yet. I have a file (data.txt) with the next information:
5,5,6,2,5,2
1,4,2,3,7,2
4,2,5,2,3,4
5,5,6,2,5,2
4,5,2,6,2,4
2,1,5,6,3,2
And i want to set to 0 all the repeated lines, for example: 5,5,6,2,5,2 appears two times, so the final file must look as follows:
0,0,0,0,0,0
1,4,2,3,7,2
4,2,5,2,3,4
0,0,0,0,0,0
4,5,2,6,2,4
2,1,5,6,3,2
I have tried with auxiliar files but cannot get the solution, i would be so apreciated with any help.
I can set any of the two lines to 0 but not both of them, and the same if the same line appears more than twice.

You can achieve that by:
Opening the input/output file on "r+" mode first
Systematically getting characters from the file line by line into an array of character arrays
Comparing lines with each other, setting characters other than commas to zero characters when they are paired
Seeking back in the file
Writing lines back into the file, separating them with new lines
To detect pairings properly, you could possibly follow the following logic:
Pick a line, create a variable along with it and set it to 1
Compare that line with the others
In case of a match, set the variable to 0 and keep on comparing your line with the rest
... until the end, replacing the non-comma characters to zero characters with each match
After checking with them all, modify or don't modify your initially picked line depending on the state of that variable which you had set to 1 initially
Here's a code that works, should work without flaw unless you have insufficient memory:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
void settozero( char * line ) {
for ( int i = 0; line[i] != '\0'; i++ )
if ( line[i] != ',' )
line[i] = '0';
}
int main( ) {
char ** lines = NULL;
FILE * input;
if ( ( input = fopen( "input", "r+" ) ) == NULL ) {
printf( "error at line %d", __LINE__ );
return -1;
}
int currentchar;
int newline = 1;
int linecount = 0;
int lineindex;
int linesize;
while ( ( currentchar = fgetc( input ) ) != EOF ) {
if ( newline ) {
linecount++;
lineindex = 0;
linesize = 128;
lines = realloc( lines, linecount * sizeof * lines );
lines[linecount - 1] = malloc( linesize );
newline = 0;
}
if ( lineindex == linesize ) {
linesize *= 3;
lines[linecount - 1] = realloc( lines[linecount - 1], linesize );
}
if ( currentchar == '\n' ) {
newline = 1;
currentchar = '\0';
}
lines[linecount - 1][lineindex++] = currentchar;
}
if ( !newline ) {
if ( lineindex == linesize )
lines[linecount - 1] = realloc( lines[linecount - 1], linesize + 1 );
lines[linecount - 1][lineindex] = '\0';
}
int * linestoskip = calloc( linecount, sizeof * linestoskip );
for ( int i = 0; i < linecount; i++ ) {
if ( linestoskip[i] )
continue;
int unique = 1;
for ( int j = i + 1; j < linecount; j++ ) {
if ( linestoskip[j] )
continue;
if ( strcmp( lines[i], lines[j] ) == 0 ) {
unique = 0;
settozero( lines[j] );
linestoskip[j] = 1;
}
}
if ( !unique )
settozero( lines[i] );
}
free( linestoskip );
fseek( input, 0L, SEEK_SET );
for ( int i = 0; i < linecount; i++ ) {
for ( int j = 0; lines[i][j] != '\0'; j++ ) {
fputc( lines[i][j], input );
}
if ( i != linecount - 1 || newline )
fputc( '\n', input );
free( lines[i] );
}
free( lines );
putchar( 10 );
return 0;
}

Related

Cannot print or access char * inside a function

The code below does not print nor return the char * temp which I am trying to retrieve from a text file containing a matrix of the form:
4
spQ77377.1 0.000000 0.776030 0.781073 0.804880
spO91086.1 0.776030 0.000000 0.564157 0.559756
spP04578.2 0.781073 0.564157 0.000000 0.302724
spO12164.1 0.804880 0.559756 0.302724 0.000000
The whole code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char * const getField( char lineBuffer[255], int field ) {
printf( "\n " );
static char temp[30];
int f = 0;
for( int i = 0; lineBuffer[i]!='\n' ; i++ ) {
if( f == field && lineBuffer[i] != ' ' ) {
temp[i] = lineBuffer[i];
printf( "%c", temp[i] );
}
if( lineBuffer[i] == ' ' && lineBuffer[i+1] == ' ' ) {
printf( "||" );
f++;
}
if( f > field ) {
printf( " break " );
printf( "*%s*", temp );
fflush(stdout);
return temp;
}
}
return "!";
}
int main() {
FILE *matrixStream;
matrixStream = fopen( "outfile", "r" );
if ( matrixStream == NULL ) {
printf( "\n\tERROR FILE NOT FOUND!\n" );
exit( 1 );
}
char lineBuffer[255];
fseek( matrixStream, 0, SEEK_SET );
int line = 0;
char ** field1 = malloc( 4 * sizeof( char *) );
while( fgets( lineBuffer, 255, matrixStream ) ) {
if( line != 0 ) {
printf( "\n line = %d ", line-1 );
if( line == 1 ) {
field1[line-1] = malloc( 30 * sizeof( char ) );
strcpy( field1[line-1], getField( lineBuffer, 1 ) );
}
}
line++;
}
printf( "\n" );
fclose( matrixStream );
return 0;
}
My objective is to have the function getField() to return a certain field or column (provided in argument as int field) for a line in the matrix.
For now, I only have the following output and can not seem to understand the problem, there are no error message during compilation with the options -Wall -pedantic. Here is the exact output:
line = 0
||0.000000|| break **
line = 1
line = 2
line = 3
The value of char * temp is not printed between the * characters as it should be.
Thank you in advance for any help or advice you can provide.
you need to terminate your temp buffer, and to have 2 indexes
static char temp[30];
int toff = 0; // temp offset
int f = 0;
for( int i = 0; lineBuffer[i]!='\n' ; i++ ) {
if( f == field && lineBuffer[i] != ' ' ) {
temp[toff++] = lineBuffer[i]; // use temp offset
printf( "%c", temp[i] );
}
if( lineBuffer[i] == ' ' && lineBuffer[i+1] == ' ' ) {
printf( "||" );
f++;
}
if( f > field ) {
temp[toff] = 0; // 0 terminate
printf( " break " );
printf( "*%s*", temp );
fflush(stdout);
return temp;
}
}
of course you should also error out if toff > sizeof(temp)
BTW the reason you get nothing is that temp, being static, is initialized to 0 at startup and you never write anything to temp[0] (beacuse you use the line buffer offset). So temp is an empty string always

Output a string with a new character in each line, forming a right triangle

Trying to output a string that has been assigned to an array, with different characters on each new line, eventually creating a right triangle. But I'm completely stuck. I believe some for loops should be involved to iterate over each character but I don't know how to increase the array index on each new line to output one character more than the line before.
This is a sketch that allowed me to visualize this:
string[0]
string[1] + string[2]
string[3] + string[4] + string[5]
string[6] + string[7] + string[8] + string[9]
For example, let's take into account this line of code: char string[50] = "Assignment";
The output desired would look like this:
A
s s
i g n
m e n t
Any guidance would be appreciated.
You can do it using only one while loop.
Here is a demonstrative program
#include <stdio.h>
void triangle_output( const char *s )
{
size_t n = 1;
size_t i = n;
while ( *s )
{
if ( i-- == 0 )
{
putchar( '\n' );
i = n++;
}
putchar( *s++ );
putchar( ' ' );
}
if ( i != n - 1 ) putchar( '\n' );
}
int main(void)
{
char *s = "Assignment";
triangle_output( s );
return 0;
}
The program output is
A
s s
i g n
m e n t
Or the function can be rewritten the following way
void triangle_output( const char *s )
{
size_t n = 1;
size_t i = 0;
while ( *s )
{
putchar( *s++ );
putchar( ' ' );
if ( ++i == n )
{
putchar( '\n' );
i = 0;
++n;
}
}
if ( i != 0 ) putchar( '\n' );
}
This function will print the triangle. If the string have enough chars to print the whole last line it will print -.
void printTriangle(const char *s)
{
size_t length = strlen(s), pos = 0;
for(size_t line = 1; line < -1; line++)
{
for(size_t ch = 1; ch <= line; ch++)
{
if(pos < length) printf("%c", *s++);
else printf("-");
pos++;
}
printf("\n");
if(pos >= length) break;
}
}
int main(void)
{
printTriangle("Assignment123");
}
https://godbolt.org/z/xxM1eEY6a

How to properly change elements in a char [] in c

I am trying to create a function that takes in word from a file then normalizes it by deleting any punctuation or quotes. The problem I am having is that when I have a word that has " in the front or both the front and back like "how", I get out put like this:
"howw"
howwETX
"well
"wel
How do I stop this from happening?
char *normalize( int count, char entry[], char output[] ){
count--;/* to allow for the zero index of an array*/
if( entry[0] == '"' && entry[count] == '"' ){
for(int i=1 , j=0;j < count - 1; i++,j++ ){
output[j] = entry[i];
}
output[count + 1 ] = '\0';
return output;
}else if( entry[0] == '"' ){
for(int i = 0 , j=0; j < count; i++, j++ ){
output[j] = entry[i];
}
output[count++] = '\0';
return output;
} else if( entry[count] == '"' || ispunct( entry[count] ) ){
for(int i=0 , j=0;i < count; i++,j++ ){
output[j] = entry[i];
}
output[count] = '\0';
return output;
}
return entry;
}/* ends normalize( int count, char entry[], char output[] )*/
Let's play debugger. Suppose your input is this:
entry == "a"
count == 3
We begin executing, and here's what happens:
count == 2
i == 1
j == 0
output[0] == 'a'
The loop exits and then:
output[3] == '\0'
So now output contains aa", which is incorrect. The solution is to set output[count-1] to null when the loop exits, not count + 1.
You are not counting your indices correctly.
In the case where there are quotes front and back, the length of the output string is count - 1, after count has been updated, so you should set output[count - 1] = '\0' rather than output[count + 1] = '\0'. In fact, you may want to decalre j outside your loop and use output[j] since that will be the correct position in the string (in all three cases).
In the case where only the first character is a quote, you should skip the quote: i = 1, not i = 0.
Try the following. At least it is correct and looks simpler.:)
char * normalize( char output[], const char entry[], size_t n )
{
if ( n != 0 && entry[0] == '"' )
{
++entry;
--n;
}
if ( n != 0 && ispunct( entry[n-1] ) )
{
--n;
}
strncpy( output, entry, n );
output[n] = '\0';
return output;
}

checking chars when reading from file with getc

In the following code, I'm attempting to store all characters from a file (including newlines).
If a newline is read, variable 'i' should be incremented and 'j' reset to 0, but this doesn't happen. I've confirmed that the newlines are in fact being read and stored, by printing from my array to console.
void scan_solved_nonogram(board *b) {
FILE *file = fopen("test.txt", "r");
int i = 0, j = 0;
while( ( b->symbol[i][j] = getc(file) ) != EOF ) {
j++;
if( b->symbol[i][j] == '\n' ) {
i++;
j = 0;
}
}
fclose(file);
b->size_i = i;
b->size_j = j;
}
The problem is that you increment j before you check for the newline character.
while( ( b->symbol[i][j] = getc(file) ) != EOF ) {
j++;// you increment j, so you need to check for newline at j-1
if( b->symbol[i][j-1] == '\n' ) {
i++;
j = 0;
}
}

Trouble with dynamic input program in C

I am having debugging my program and I cannot seem to find any answers. My program takes in a file, copies the words to a dynamic array and keeps a word count for multiples.
Problem 1) For what I have compiled I have tried to different input examples. One reads "foo bar bat bam" and the other "foo foo bar bam". The first output is all four words in that order, the second prints
foo
bar
bam
foo bar bam
I cannot figure out why this is.
Problem 2) I am getting a segmentation fault when I try to initialize a newly entered word to count 1. The line
arrayOfWords[unique_words].count = 1;
is giving me a segmentation fault. And using -> does not compile.
Problem 3) I cannot seem to dynamically grow the array. I commented them out for now, but you can see my two strategies at attempting to enlarge the array.
I SERIOUSLY APPRECIATE YOUR HELP!
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INITIAL_SIZE 10
typedef unsigned int uint;
typedef struct { char * word; int count; } wordType;
int main( void )
{
wordType *arrayOfWords = (wordType*)malloc(1 * sizeof (wordType) );
wordType *tempArray;
FILE * inputFile;
char temp[50];
uint i;
uint j;
uint unique_words;
uint exists;
uint wordAdded;
inputFile = fopen( "input.txt", "r");
if( inputFile == NULL )
{
printf("Error: File could not be opened\n" );
/*report failure*/
return 1;
}
i = 0;
unique_words = 0;
wordAdded = 0;
while( fscanf( inputFile, "%s", temp) != EOF )
{
/*if a word was added, then increase the size by one
if( wordAdded == 1 )
{
tempArray = malloc((unique_words + 1) * sizeof(wordType) );
memcpy( arrayOfWords, tempArray, unique_words + 1 );
free( tempArray );
wordAdded = 0;
} */
/*
if( wordAdded == 1 )
{
arrayOfWords = realloc(arrayOfWords, unique_words + 1 );
wordAdded = 0;
}*/
exists = 0;
for( j = 0; j < unique_words; j++ )
{
if( strcmp( arrayOfWords[j].word, temp ) == 0 )
{
arrayOfWords[j].count++;
exists = 1;
}
}
if( exists == 0 )
{
arrayOfWords[unique_words].word = malloc(sizeof(char)
* (strlen(temp)+1));
strcpy( arrayOfWords[unique_words].word, temp );
/*arrayOfWords[unique_words].count = 1; */
unique_words++;
wordAdded = 1;
}
i++;
}
printf("unique_words = %d\n", unique_words);
for( i = 0; i < unique_words; i++ )
printf("%s\n", arrayOfWords[i].word);
fclose( inputFile );
/* for( i = 0; i < size; i++ )
free( arrayOfWords[0].word );*/
return 0;
}
int main( void ){
wordType *arrayOfWords = NULL;
FILE * inputFile = stdin; //stdin for simplification
char temp[50];
uint i,j;
uint unique_words;
uint exists;
unique_words = 0;
while( fscanf( inputFile, "%s", temp) != EOF ){
exists = 0;
for( j = 0; j < unique_words; j++ ){
if( strcmp( arrayOfWords[j].word, temp ) == 0 ){
arrayOfWords[j].count++;
exists = 1;
break;
}
}
if( exists == 0){//new word
arrayOfWords = realloc(arrayOfWords, (unique_words+1)*sizeof(wordType));
arrayOfWords[unique_words].count = 1;
arrayOfWords[unique_words].word = malloc(sizeof(char)*(strlen(temp)+1));
strcpy(arrayOfWords[unique_words].word, temp );
++unique_words;
}
}
printf("unique_words = %d\n", unique_words);
for( i = 0; i < unique_words; i++ )
printf("%s\n", arrayOfWords[i].word);
/* deallcate
for( i = 0; i < unique_words; ++i)
free( arrayOfWords[i].word );
free(arraOfWords);
*/
return 0;
}
You commented out the reallocation because it didn't work, and now it crashes because you don't reallocate.
Just like malloc, the realloc function needs the size in bytes. You should therefore use e.g.
arrayOfWords = realloc(arrayOfWords, sizeof(wordType) * (unique_words + 1));
When you get this reallocation working, your program should no longer crash.
And in case you're wondering, the crash is because you increase unique_words but do not reallocate the buffer. This leads you to access memory outside of the memory you allocated, which is undefined behavior and can lead to crashes (or other weird behavior).

Resources