Reputation: 215
The code below works perfectly for what we need, but we were told late in the week that we cannot use strcmp as we have not covered it yet. Have you guys any suggestion of what i could use instead. I got help with the original code as i am new to pointers. Thanks
Ok this is my new code. It is not sorting the text though.
I'm new so go easy
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Function for reading unsorted data from a file
int read(const char *filename, char* arr[]);
// Function for sorting gathered data in array
void sort(char* arr[], int N);
int my_strcmp(const char *a, const char *b);
// Function for writing sorted data to file
int write(const char *filename, char* arr[], int N);
// Helper function for swapping two words
void swap(char** a, char** b);
// Helper function for dealocatiing memory used by array
void final(char* arr[], int N);
int main(int argc, char *argv[])
{
char filename[260];
char* arr[1000]; // Suppose there are no more than 1000 lines
int N; // Size of filled array
// Request for input file name
printf("Input file name : ");
scanf("%s",filename);
// Perform reading file
if (-1 == (N = read(filename,arr))) {
// If error occure while opening the file
printf("File can't be opened.\n");
system("PAUSE");
return 0;
}
// Sort the data
sort(arr,N);
printf("Data sorted successfully.\n");
// Request for output file name
printf("Output file name : ");
scanf("%s",filename);
// Output sorted data
if (-1 == (N = write(filename,arr,N))) {
// If error occure while opening the file
printf("File can't be opened.\n");
system("PAUSE");
return 0;
}
system("PAUSE");
// Deallocate used memory
final(arr,N);
return 0;
}
int read(const char *filename, char* arr[])
{
char buffer[512]; // Suppose that line can't be longer than 511 symbols
int i = 0, len;
FILE * infile; // Input file
// Open file for reading
infile = fopen(filename,"r");
// Check whether file was opened correctly
if (!infile)
// If not then return error code
return -1;
// Read data
while (!feof(infile)) {
// Read one line (word)
fscanf(infile,"%s",buffer);
// Find the length of this word
len = strlen(buffer);
// Allocate memory for the word...
arr[i] = (char*)malloc(len+1);
// And copy the word to array
strcpy(arr[i],buffer);
// Increase counter
++i;
}
// Close the file
fclose(infile);
// Return number of elements of created array
return i;
}
void sort(char* arr[], int N)
{
int i,cmp;
for (--N; N>0; --N)
for (i=0; i<N; ++i) {
// Compare two words
cmp = my_strcmp(arr[i],arr[i+1]);
// If the first one is greater than second one (in alphabetical meaning)...
if (cmp>0)
// ...then swap them
swap(&arr[i],&arr[i+1]);
}
}
int write(const char *filename, char* arr[], int N)
{
int i;
FILE * outfile; // Output file
// Open file for writing
outfile = fopen(filename,"w");
// Check whether file was opened correctly
if (!outfile)
// If not then return error code
return -1;
// Write data
for (i=0; i<N-1; ++i)
// After each word output sign '\n' which means "new line"
fprintf(outfile,"%s\n",arr[i]);
// But after the last word don't write "new line"
fprintf(outfile,"%s",arr[N-1]);
// Close the file
fclose(outfile);
// Return success code
return 0;
}
void swap(char** a, char** b)
{
char *temp = *a;
*a = *b;
*b = temp;
}
void final(char* arr[], int N)
{
int i;
for (i=0; i<N; ++i)
free(arr[i]);
}
int my_strcmp(const char *a, const char *b)
{
while(*a==*b)
{
if ( *a == '\0' || *b == '\0' )
break;
a++;
b++;
}
if( *a == '\0' && *b == '\0' )
return 0;
else
return -1;
}
Upvotes: 0
Views: 1500
Reputation: 764
As @Gopi and @iharob suggested, you should write a strcmp
replacement. First, remember to add a declaration before main with the same signature as strcmp:
int my_strcmp(const char *a,const char *b);
Also remember to change the cmp = strcmp(arr[i],arr[i+1]);
call in the sort function to the new name cmp = my_strcmp(arr[i], arr[i+1]);
.
Then write your own strcmp version. It's a simple function and you have already described what it does. cppreference gives a complete description of the function:
Defined in header
int strcmp( const char *lhs, constchar *rhs );
Compares two null-terminated byte strings lexicographically.
The sign of the result is the sign of the difference between the values of the first pair of characters (both interpreted as unsigned char) that differ in the strings being compared.
The behavior is undefined if lhs or rhs are not pointers to null-terminated strings.
Parameters
lhs, rhs - pointers to the null-terminated byte strings to compare.
Return value
Negative value if lhs appears before rhs in lexicographical order.
Zero if lhs and rhs compare equal.
Positive value if lhs appears after rhs in lexicographical order.
You a have already described a simple implementation: "compare the first character of each string and if they are equal, compare the next two". If they aren't equal, you return a negative value if the first comes before the second in a lexicographical order and a positive value if it is the opposite. You return 0 if the strings are all equal.
int my_strcmp(const char *a, const char *b)
{
/* Your code here */
}
Things to have in mind:
'\0'
character, so you use that to test the end of a string. You can iterate over the whole string either incrementing the pointer or indexing it like an array and incrementing the index.Edit: Discussing your newly added function implementation. I won't provide an optimal or beautiful implementation, I will just discuss your code with the intention of helping you to achieve something that works correctly starting from the code you posted.
Your code (with better indentation):
int my_strcmp(const char *a, const char *b)
{
while(*a==*b)
{
if ( *a == '\0' || *b == '\0' )
break;
a++;
b++;
}
if( *a == '\0' && *b == '\0' )
return 0;
else
return -1;
}
The while
loop iterates over both strings while they're equal. You also break the loop if you have reached the end of one of the strings by testing for the '\0'
character. That's all very good. Your problem is after the loop.
There are four possible states after the loop:
*a
and *b
are '\0'
. That means that all characters were equal and the strings are, therefore, equal.*a
is '\0'
, but *b
is a valid character. That means that the first string is shorter than the second, but they were equal up to the point that the first ended. That means that the first comes before the second.*b
is '\0'
and *a
is a valid character. That means the second comes before the first.*a
and *b
are valid characters, they are just different. Testing the characters will define which string comes first.Remember that you should return a negative value if the first string comes before the second, 0 if they are equal or a positive value the second string comes before the first. You could just test all possible states naively and return the appropriate value. After you have a working implementation, you can think about how you could keep the same behaviour while "cutting corners" to make it more succinct if needed.
Upvotes: 1