C program using malloc and strcat prints nonsense [duplicate] - c

I want to shift elements in my array to right and fill the shifted elements with zero (as string) . but it's a bit more difficult than i thought.
this program reads a text file containing two lines. each line contains of an integer (maximum length is defined). it saves each line in a separate array.
I need to convert these two arrays to integer array later and do some arithmetic operations.
so for that, i need to make sure that these two arrays have the same length
for example my input is:
num_first : 1859654
num_second: 5654
now i need them to be:
num_First : 1859654 (it's larger than second number so it doesn't change)
num second: 0005654 (smaller than first, so we need to add those leading zeros)
how do i add those leading zeros to array based on difference of two input??
and at last i want to save them in arrays (as string or integer).
#include <stdio.h>
#include <string.h>
#define SIZE_MAX 20
int main()
{
FILE *fPTR;
char num_first[SIZE_MAX]; // string input
char num_second[SIZE_MAX];
if ((fPTR = fopen("input.txt", "r")) == NULL) // our file contains two line of integers. one at each
{
puts("File could not be opened.");
}
else
{
if (fgets(num_first, SIZE_MAX, fPTR) != NULL) // reads first line and saves to num_first
puts(num_first); // prints first number
if (fgets(num_second, SIZE_MAX, fPTR) != NULL) // reads second line and saves to num_second
puts(num_second); // prints second number
fclose(fPTR);
}
// getting strings lengths
int fLEN = strlen(num_first) - 1;
int sLEN = strlen(num_second);
int e = 0; // difference between two string lengths
// here we get the difference and it's the place which i want to shif the arrays
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
}
else if (sLEN>fLEN) // second string is bigger than first
{
e = sLEN-fLEN;
}
else // there is no difference between two strings
{
e = fLEN-sLEN;
}
}
edit: i also got another idea but it doesn't work as intended.
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
for(i=e;i>=0;i--)
{
num_second[i+1] = num_second[i];
}
for(i=fLEN-e;i>=0;i--)
{
num_second[i] = '0';
}
}
edit 2: (slowly started to working) prints more zero. trying to fix it
#include <stdio.h>
#include <string.h>
#define SIZE_MAX 20
int main()
{
FILE *fPTR;
char num_first[SIZE_MAX]; // string input
char num_second[SIZE_MAX];
char num_second2[SIZE_MAX] = {0};
int i = 0;
char numbers[SIZE_MAX];
if ((fPTR = fopen("input.txt", "r")) == NULL) // our file contains two line of integers. one at each
{
puts("File could not be opened.");
}
else
{
if (fgets(num_first, SIZE_MAX, fPTR) != NULL) // reads first line and saves to num_first
puts(num_first); // prints first number
if (fgets(num_second, SIZE_MAX, fPTR) != NULL) // reads second line and saves to num_second
puts(num_second); // prints second number
fclose(fPTR);
}
// getting strings lengths
int fLEN = strlen(num_first) - 1;
int sLEN = strlen(num_second);
int e = 0; // difference between two string lengths
int h = 4;
// here we get the difference and it's the place which i want to shif the arrays
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
while (i>= h)//for(i=e;i>=0;i--)
{
num_second2[i+h] = num_second[i];
i++;
h--;
}
for(i=fLEN-e;i>=0;i--)
{
// num_second[i] = '0';
}
}
else if (sLEN>fLEN) // second string is bigger than first
{
e = sLEN-fLEN;
}
else // there is no difference between two strings
{
e = fLEN-sLEN;
}
printf("\n%d\n", e);
for (i = 0; i < SIZE_MAX; i++) // using c to print
{
printf("%d", num_second2[i]);
}
puts(num_second);
}

#include <stdio.h>
#include <string.h>
#define SIZE_MAX 20
int main()
{
FILE *fPTR;
char num_first[SIZE_MAX]; // string input
char num_second[SIZE_MAX];
char num_zeros[SIZE_MAX];//array for leading zeros
int i = 0;
char numbers[SIZE_MAX];
if ((fPTR = fopen("input.txt", "r")) == NULL) // our file contains two line of integers. one at each
{
puts("File could not be opened.");
}
else
{
if (fgets(num_first, SIZE_MAX, fPTR) != NULL) // reads first line and saves to num_first
puts(num_first); // prints first number
if (fgets(num_second, SIZE_MAX, fPTR) != NULL) // reads second line and saves to num_second
puts(num_second); // prints second number
fclose(fPTR);
}
for ( i = 0; i < SIZE_MAX; i++)
{
num_zeros[i] = '0';//fill array with '0's
}
// getting strings lengths
int fLEN = strlen(num_first);
if ( fLEN && num_first[fLEN - 1] == '\n')
{
num_first[fLEN - 1] = '\0';//remove trailing newline
fLEN--;
}
int sLEN = strlen(num_second);
if ( sLEN && num_second[sLEN - 1] == '\n')
{
num_second[sLEN - 1] = '\0';//remove trailing newline
sLEN--;
}
int e = 0; // difference between two string lengths
// here we get the difference and it's the place which i want to shif the arrays
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
num_zeros[e] = '\0';//terminate array leaving e leading zeros
strcat ( num_zeros, num_second);
strcpy ( num_second, num_zeros);
}
else if (sLEN>fLEN) // second string is bigger than first
{
e = sLEN-fLEN;
while ( fLEN >= 0)//start at end of array
{
num_first[fLEN + e] = num_first[fLEN];//copy each element e items from current location
fLEN--;// decrement length
}
while ( e)// number of leading zeros
{
e--;
num_first[e] = '0';// set first e elements to '0'
}
}
else // there is no difference between two strings
{
//e = fLEN-sLEN;
}
puts(num_first);
puts(num_second);
return 0;
}

Good start with your code.
Since you're reading strings you can just use string manipulation.
If you wanted to read them as ints you could determine the size with a logarithm function, but that would be overkill.
You could save the numbers as ints, but then you'd have to defer the padding until you printed them later or saved them to a file.
The easiest way to left pad the numbers with zeroes would be to use sprintf() with the correct format specifier to right justify the number. Then you can iterate through each character of the result and replace space e.g. ' ' with '0'. That will create left-side 0-padded entries. E.g. sprintf right justifies your number in a buffer that has room to hold the max sized number you can read, leaving spaces on the left.
Then in a loop indexing one character at a time in the entry, and based on MAX_NUMBER_LEN shown below, you skip extra spaces on the left you don't want zeroes in (e.g. MAX_NUMBER_LEN - maxPaddingLenYouCalculateAtRuntime), and start replacing with zeroes.
Then it's just a matter of creating a buffer whose address you'll pass to sprintf() that has enough space allocated to hold the result. That will have to be as big or bigger than your max length. I would call it maxStrLen rather than e, because naming variables for what they're used for makes for an easier to understand and maintain program.
You have a few choices as to how to allocate that buffer of the right size, including using malloc(). But it is probably easier to determine the maximum size that an integer could be. There's even a C constant that tells you what a 32-bit or 64 bit Integer max. value is, and create an char array of fixed length entries based on that size in advance.
For example:
#define MAX_ENTRIES = 10
#define MAX_NUMBER_LEN = 15
char numbers[MAX_ENTRIES][MAX_NUMBER_LEN]
That would give you the storage to store your sprintf() results in.
Example:
sprintf(numbers[entryNumber], "*right-justifying format specifier you look up*", numberReadFromFile)
Wherein entryNumber is which slot in the array you want to store the result.
The MAX_NUMBER_LEN part you don't need to include when getting the address for sprintf (notice I just passed in numbers[entryNumber], but not the 2nd set of brackets, intentionally). Because by omitting the second set of brackets, you're saying you want the address of the specific [MAX_NUMBER_LEN] chunk corresponding to the entryNumber, inside the numbers array. Note, there is no & on numberReadFromFile either, because you are reading them into a char array as strings, and because you're passing the address of the first char of an array you can just pass the array name. Alternatively you could pass in &numberReadFromFile[0] to get the address of the first element to pass to sprintf().
And when using arrays that way, you don't need the & character to get the variable address to pass to sprintf(), as you would if you were not passing in an array element, because arrays really are simply another notation for pointers in C, and understanding how that works in general is the key to being effective with C in general and worth the initial struggle to comprehend.
Here's an example of how to do the actual zero padding, based on what you got into your array from sprintf. I won't code up a full example because learning C is about the struggle to actually do it yourself. There's no shortcut to real comprehension. I'm giving you the hardest to discover aspects, by you working it through and making a solution of it, you'll gain quite a bit of mastery. This code is off the top of my head, not compiled and tested. It would either work or be close to working.
/* numberToPad is a buffer containing a right-justified number, e.g. a number
* shifted-right by sprintf(), in a buffer sized 15 characters,
* space-padded on the left by sprintf's right-justifying format specifier.
* We want to convert the number to a 10-digit zero-padded number
* inside a 15 character field. The result should be 4 spaces, followed
* by some zeroes, followed by non-zero digits, followed by null-terminator.
* example: "ƀƀƀƀ0000012345\0" where ƀ is a space character.
*/
#define MAX_NUMBER_LEN 15 /* note: 15 includes null-terminator of string */
int maxNumberLenActuallyRead = 10;
int startZeroPaddingPos = MAX_NUMBER_LEN - maxNumberLenActuallyRead
char numberToPad[MAX_NUMBER_LEN];
int i;
for (i = 0; i < MAX_NUMBER_LEN; i++) {
if (i < startZeroPaddingPos)
continue;
if (numberToPad[i] == ' ')
numberToPad[i] = '0';
}

Related

How to verify input format without using arrays, ex input "OIL2932"

Hi I'm having a really hard time reading user input in C a specific way...
I want to read a users input, in which case my program will verify the first three characters as characters and the last four digits as digits.
And I don't know how to make sure that their input is 7 characters in total (3 chars, 4 ints) ex: ULI0788.
I don't want to use arrays, ex arr[12];
Currently I am at the point where I'm learning memory allocation & pointers, thus I am encouraged to use this rather than arrays if possible
for example
char itemID;
printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
scanf("%s", itemID);
I've done some googling and tried user suggestions but none do both of what I'm looking for, verifying each character/digit and setting a max of 7 total characters/digits. Or I just don't understand properly how to use the suggestions
googled
googled2
googled3
googled4
googled5
googled6
googled7
googled8
googled9
googled10
"I want to read a users input, in which case my program will verify the first three characters as characters and the last four digits as digits. And I don't know how to make sure that their input is 7 characters in total (3 chars, 4 ints)...I don't want to use arrays"
Without the ability to use C strings, the above is constrained to simply inputting a series of characters, then treating and testing them as discrete items:
bool test7char(void)
{
int Char;
for(int i=0;i<7;i++)
{
Char = getc(stdin);
if(i<3)
{
if(!isalpha(Char)) return false;
}
else if(!isdigit(Char)) return false;
}
return true;
}
Usage:
int main(void)
{
printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
while(!test7char())
{
printf("Mistake - Re-enter an ID of ITEM. (max 3 characters, 4 digits)");
}
return 0;
}
EDIT - "I am just trying to figure out how to answer my question using memory allocation & maybe pointers"
Using pointer: (In memory, this pointer will point to a series of alphanumeric characters, terminated by \0, i.e. a string.)
#define STR_SIZE 7 + 1
BOOL test7char(const char *str);
int main(void)
{
char *str = calloc(STR_SIZE, 1);
if(str)
{
printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
if(fgets(str, STR_SIZE, stdin))
{
while(!test7char(str))
{
printf("\nMistake - Re-enter an ID of ITEM. (max 3 characters, 4 digits)");
if(!fgets(str, STR_SIZE, stdin))
{
//message user of error
break;
}
}
}
free(str);
}
return 0;
}
bool test7char(const char *str)
{
if(!str) return false;
if(strlen(str) != STR_SIZE -1) return false;
for(int i=0;i<7;i++)
{
if(i<3)
{
if(!isalpha(str[i])) return false;
}
else if(!isdigit(str[i])) return false;
}
return true;
}
I would advise you to use both fgets and sscanf:
fgets allows you to read a certain number of characters (which can be read from stdin).
sscanf allows you to read formatted input from a string (which you got from fgets).
By combining those, you can read 7 characters from standard input (8 if you add the \0) and then parse those to get the two values you're looking for.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
// 8 chars long for string and terminating `\0`
char *ID = calloc(8, 1);
// extra char for same reason as above
char *IDchar = calloc(4, 1);
int IDnum, processed;
// get the string and verify it's 7 characters long
if (fgets(ID, 8, stdin) && strlen(ID) == 7)
sscanf(ID, "%3s%4d%n", IDchar, &IDnum, &processed);
if (processed == 7)
printf("success");
else
printf("failure");
}
The %n will collect the number of characters processed by the sscanf, ensuring you parsed the right number of characters.
note that this is a VERY dangerous parameter, and you should always verify your input length before using it.
Edit:
If you do not want to use arrays at all, and only want to verify the input format without storing or reusing it, you can use getc to read the characters one at a time and verify their value:
#include <stdio.h>
#include <ctype.h>
int isEnd(int c)
{
return c == '\n' || c == EOF;
}
void main()
{
int tmp;
int valid = 1;
//check the first 3 characters
for(int v = 0; v < 3 && valid; v++)
{
// read a char on standard input
tmp = fgetc(stdin);
// check if tmp is a letter
valid = islower(tmp) || isupper(tmp);
}
//check the next 4 characters
for(int v = 0; v < 4 && valid; v++)
{
// read a char on standard input
tmp = fgetc(stdin);
// check if tmp is a numeral
valid = isdigit(tmp);
}
if (valid)
{
printf("format OK\n");
// Check that the input is finished (only if format is OK)
tmp = fgetc(stdin);
if (isEnd(tmp))
printf("length OK\n");
else
printf("length KO: %d\n", tmp);
}
else
{
printf("format KO\n");
}
}
As I said before, this will only check the validity of the input, not store it or allow you to reuse it. But it does not use arrays.
Edit 2:
Another thing to watch out for with fgetc or getc is that, though it will manage longer inputs properly, it will get stuck waiting for the chars to be provided if there aren't enough. Thus make sure to exit the moment you read an incorrect character (if it's an end-of-line char, there won't be any more coming)
Edit 3:
Of course I'd forgotten malloc.
Edited the first answer.

How can I create a 2D array to store a collection of words scanned from a .txt file in C?

I am working on a program where I want to scan a .txt file that contains a poem. After scanning the poem, I want to be able to store each individual word as a single string and store those strings in a 2D array. For example, if my .txt file contains the following:
Haikus are easy.
But sometimes they don't make sense.
Refrigerator.
I want to be able to store each word as the following in a single array:
H a i k u s \0
a r e \0
e a s y . \0
B u t \0
s o m e t i m e s \0
t h e y \0
d o n ' t \0
m a k e \0
s e n s e . \0
R e f r i g e r a t o r . \0
So far, this is the code I have. I am having difficulties understanding 2D arrays, so if someone could explain that to me as well in context to this problem, that would be great. I am still learning the C language, so it takes time for me to understand some things. I have been scratching my head at this for a few hours now and am using this as help after trying everything I could think of!
The following is my function for getting the words and storing them in to arrays (it also returns the number of words there are, which is used separately for a different part of the program):
int getWords(int maxSize, FILE* inFile, char strings[][COL_SIZE]){
int numWords;
for(int i = 0; i < maxSize; i++){
fscanf(inFile, "%s", strings[i]);
while(fscanf(inFile, "%s", strings[i] == 10){
numWords++;
}
}
return numWords;
}
Here's the code I have where I call the function in the main function (I am not sure what numbers to set the COL_SIZE and MAX_LENGTH to, like I said, I am new to this and am trying my best to understand 2D arrays and how they work):
#define COL_SIZE 10
#define MAX_LENGTH 500
int main(){
FILE* fp;
char strArray[MAX_LENGTH][COL_SIZE];
fp = fopen(FILE_NAME, "r");
if(fp == NULL){
printf("File could not be found!");
}
else{
getWords(MAX_LENGTH, fp, strArray);
fclose(fp);
}
return 0;
}
What you are not understanding, it that COL_SIZE must be large enough to store the longest word +1 for the nul-terminating character. Take:
R e f r i g e r a t o r . \0
----------------------------
1 2 3 4 5 6 7 8 9 0 1 2 3 4 - > 14 characters of storage required
You declare a 500 x 10 2D array of char:
char strArray[500][10]
"Refrigertator." cannot fit in strArray, so what happens is "Refrigerat" is stored at one row-index, and then "tor.\0" overwrites the first 5 characters of the next.
There are a number of ways to handle the input, but if you want to use fscanf, then you need (1) to include a field-width modifier with the string conversion to limit the number of characters stored to the amount of storage available, and (2) validate the next character after those you have read is a whitespace character, e.g.
#include <ctype.h>
int getWords(int maxSize, FILE* inFile, char strings[][COL_SIZE])
{
char c;
int n = 0;
while (n < maxSize) {
int rtn = fscanf (inFile, "%9s%c", strings[n], &c);
if (rtn == 2 && isspace(c))
n++;
else if (rtn == 1) {
n++;
break;
}
else
break;
}
return n;
}
Note the format string contains a field-width modifier of one-less than the total number of characters available, and then the character conversion stores the next character and validates it is whitespace (if it isn't you have a word that is too long to fit in your array)
With any user-input function, you cannot use it correctly unless you check the return. Above, the return from fscanf() is saved in rtn. If you have a successful conversion of both your string limited to COL_SIZE - 1 by your field-width modifier and c is whitespace, you have a successful read of the word and you are not yet at EOF. If the return is 1, you have the successful read of the word and you have reached EOF (non-POSIX line end on last line). Otherwise, you will either reach the limit of MAX_LENGTH and exit the loop, or your will reach EOF and fscanf() will return EOF forcing an exit of the loop through the else clause.
Lastly, don't skimp on buffer size. The longest word in the non-medical unabridged dictionary is 29-character, requiring a total of 30 characters storage, so #define COL_SIZE 32 makes more sense than 10.
Look things over and let me know if you have more questions.
stdio.h Only
If you are limited to stdio.h, then you can manually confirm that c contains a whitespace character:
if (rtn == 2 && (c == ' ' || c == '\t' || c == '\n'))
n++;
You probably don't want a traditional 2D array. Those are usually rectangular, which is not well suited to storing variable length words. Instead, you would want an array of pointers to buffers, sort of like argv is. Since the goal is to load from a file, I suggest using a contiguous buffer rather than allocating a separate one for each word.
The general idea is this:
First pass: get total file size and read in the whole thing (+1 byte for trailing NUL).
Second pass: count the words and split them with NULs.
Third pass: allocate a buffer for the word pointers and fill it in
Here's how to load the entire file:
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
char *load_file(const char *fname, int *n)
{
struct stat st;
if(stat(fname, &st) == -1 || st.st_size == 0) return NULL;
char *buffer = malloc(st.st_size + 1);
if(buffer == NULL) return NULL;
FILE *file = fopen(fname, "r");
if(file == NULL || fread(buffer, 1, st.st_size, file)) {
free(buffer);
buffer = NULL;
}
fclose(file);
*n = st.st_size;
return buffer;
}
You can count the words by just stepping through the file contents and marking the end of each word.
#include <ctype.h>
char *skip_nonword(char *text, char *end)
{
while(text != end && !isalpha(*text)) text++;
return text;
}
char *skip_word(char *text, char *end)
{
while(text != end && isalpha(*text)) text++;
return text;
}
int count_words(char *text, int n)
{
char *end = text + n;
int count = 0;
while(text < end) {
text = skip_nonword(text, end);
if(text < end) {
count++;
text = skip_word(text, end);
*text = '\0';
}
}
return count;
}
Now you are in position to allocate the word buffer and fill it in:
char **list_words(const char *text, int n, int count)
{
char *end = text + n;
char **words = malloc(count * sizeof(char *));
if(words == NULL) return NULL;
for(int i = 0; i < count; i++) {
words[i] = skip_nonword(text, end);
text = skip_word(words[i], end);
}
return words;
}

How do I separate integers that contain commas from a text file using Strtol in C programming?

There are approximately 150,000 numbers in a text file. These numbers consist of one line. I'm supposed to seperate these by commas. But I'm not allowed to use a fixed-size array. I thought about seperating the numbers I got by the strtol function. But I couldn't find how I can.
The second parameter to strtol (and similar functions) is the address of a char* variable:
long strtol(const char* str, char** endptr, int base);
If the argument is not NULL, it must point to a char*, which will be filled in with the address of the first character in str not consumed by strtol. In the case of comma-separated numbers, this will be the address of the comma (except in the case of the last number in the list).
You can easily use that to read all the numbers in sequence:
char* end = ",";
for (const char* p = buffer; *end == ','; p = end + 1) {
long number = strtol(p, &end, 0);
if (end == p) break; /* There was no number */
/* check for other errors */
/* store the number in a dynamic array */
}
if (*end != '\n' && *end != '\0') {
/* Input was not as expected. Signal error */
}
The for loop starts a pointer at the first character in the string, and checks to make sure that the previous number was terminated with a comma. (We initialise the end pointer to point at a comma so that this test works on the first iteration.) At the end of the loop, it moves p over the terminator (whatever it was) and continues.
It is unclear what you mean by I'm not allowed to use a fixed-size array: let's assume you are supposed to allocate the array for the values and make no assumptions about the maximum number of items.
you should not try and read the file into an array of char, with fgets() or fwrite(), because this array would need to be very large and there is no way to tell in advance how large to allocate it. Hence strtol() is not the right tool.
a simpler alternative is to read the text file one byte at a time and compute the numbers on the fly, or use fscanf():
#include <stdio.h>
#include <stdlib.h>
/* read all numbers separated by `,` into an allocated array.
*ptr -> pointer to the allocated array
*psize -> allocated size of the array
return value: number of values read
*/
int read_numbers(FILE *fp, int **ptr, int *psize) {
int *array;
int n, size;
int num;
*ptr = array = NULL;
*psize = size = n = 0;
while (fscanf(fp, "%d,", &num) == 1) {
if (n == size) {
/* reallocate array by the golden ratio */
size = size + (size / 2) + (size / 8) + 16;
array = realloc(array, sizeof(*array) * size);
if (array == NULL) {
free(*ptr);
*ptr = NULL;
*psize = 0;
return -1; /* not enough memory */
}
*ptr = array;
*psize = size;
}
array[n++] = num;
}
return num;
}

shifting elements in an array of strings and fill with zeros

I want to shift elements in my array to right and fill the shifted elements with zero (as string) . but it's a bit more difficult than i thought.
this program reads a text file containing two lines. each line contains of an integer (maximum length is defined). it saves each line in a separate array.
I need to convert these two arrays to integer array later and do some arithmetic operations.
so for that, i need to make sure that these two arrays have the same length
for example my input is:
num_first : 1859654
num_second: 5654
now i need them to be:
num_First : 1859654 (it's larger than second number so it doesn't change)
num second: 0005654 (smaller than first, so we need to add those leading zeros)
how do i add those leading zeros to array based on difference of two input??
and at last i want to save them in arrays (as string or integer).
#include <stdio.h>
#include <string.h>
#define SIZE_MAX 20
int main()
{
FILE *fPTR;
char num_first[SIZE_MAX]; // string input
char num_second[SIZE_MAX];
if ((fPTR = fopen("input.txt", "r")) == NULL) // our file contains two line of integers. one at each
{
puts("File could not be opened.");
}
else
{
if (fgets(num_first, SIZE_MAX, fPTR) != NULL) // reads first line and saves to num_first
puts(num_first); // prints first number
if (fgets(num_second, SIZE_MAX, fPTR) != NULL) // reads second line and saves to num_second
puts(num_second); // prints second number
fclose(fPTR);
}
// getting strings lengths
int fLEN = strlen(num_first) - 1;
int sLEN = strlen(num_second);
int e = 0; // difference between two string lengths
// here we get the difference and it's the place which i want to shif the arrays
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
}
else if (sLEN>fLEN) // second string is bigger than first
{
e = sLEN-fLEN;
}
else // there is no difference between two strings
{
e = fLEN-sLEN;
}
}
edit: i also got another idea but it doesn't work as intended.
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
for(i=e;i>=0;i--)
{
num_second[i+1] = num_second[i];
}
for(i=fLEN-e;i>=0;i--)
{
num_second[i] = '0';
}
}
edit 2: (slowly started to working) prints more zero. trying to fix it
#include <stdio.h>
#include <string.h>
#define SIZE_MAX 20
int main()
{
FILE *fPTR;
char num_first[SIZE_MAX]; // string input
char num_second[SIZE_MAX];
char num_second2[SIZE_MAX] = {0};
int i = 0;
char numbers[SIZE_MAX];
if ((fPTR = fopen("input.txt", "r")) == NULL) // our file contains two line of integers. one at each
{
puts("File could not be opened.");
}
else
{
if (fgets(num_first, SIZE_MAX, fPTR) != NULL) // reads first line and saves to num_first
puts(num_first); // prints first number
if (fgets(num_second, SIZE_MAX, fPTR) != NULL) // reads second line and saves to num_second
puts(num_second); // prints second number
fclose(fPTR);
}
// getting strings lengths
int fLEN = strlen(num_first) - 1;
int sLEN = strlen(num_second);
int e = 0; // difference between two string lengths
int h = 4;
// here we get the difference and it's the place which i want to shif the arrays
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
while (i>= h)//for(i=e;i>=0;i--)
{
num_second2[i+h] = num_second[i];
i++;
h--;
}
for(i=fLEN-e;i>=0;i--)
{
// num_second[i] = '0';
}
}
else if (sLEN>fLEN) // second string is bigger than first
{
e = sLEN-fLEN;
}
else // there is no difference between two strings
{
e = fLEN-sLEN;
}
printf("\n%d\n", e);
for (i = 0; i < SIZE_MAX; i++) // using c to print
{
printf("%d", num_second2[i]);
}
puts(num_second);
}
#include <stdio.h>
#include <string.h>
#define SIZE_MAX 20
int main()
{
FILE *fPTR;
char num_first[SIZE_MAX]; // string input
char num_second[SIZE_MAX];
char num_zeros[SIZE_MAX];//array for leading zeros
int i = 0;
char numbers[SIZE_MAX];
if ((fPTR = fopen("input.txt", "r")) == NULL) // our file contains two line of integers. one at each
{
puts("File could not be opened.");
}
else
{
if (fgets(num_first, SIZE_MAX, fPTR) != NULL) // reads first line and saves to num_first
puts(num_first); // prints first number
if (fgets(num_second, SIZE_MAX, fPTR) != NULL) // reads second line and saves to num_second
puts(num_second); // prints second number
fclose(fPTR);
}
for ( i = 0; i < SIZE_MAX; i++)
{
num_zeros[i] = '0';//fill array with '0's
}
// getting strings lengths
int fLEN = strlen(num_first);
if ( fLEN && num_first[fLEN - 1] == '\n')
{
num_first[fLEN - 1] = '\0';//remove trailing newline
fLEN--;
}
int sLEN = strlen(num_second);
if ( sLEN && num_second[sLEN - 1] == '\n')
{
num_second[sLEN - 1] = '\0';//remove trailing newline
sLEN--;
}
int e = 0; // difference between two string lengths
// here we get the difference and it's the place which i want to shif the arrays
if (fLEN>sLEN) // first string is bigger than second
{
e = fLEN-sLEN;
num_zeros[e] = '\0';//terminate array leaving e leading zeros
strcat ( num_zeros, num_second);
strcpy ( num_second, num_zeros);
}
else if (sLEN>fLEN) // second string is bigger than first
{
e = sLEN-fLEN;
while ( fLEN >= 0)//start at end of array
{
num_first[fLEN + e] = num_first[fLEN];//copy each element e items from current location
fLEN--;// decrement length
}
while ( e)// number of leading zeros
{
e--;
num_first[e] = '0';// set first e elements to '0'
}
}
else // there is no difference between two strings
{
//e = fLEN-sLEN;
}
puts(num_first);
puts(num_second);
return 0;
}
Good start with your code.
Since you're reading strings you can just use string manipulation.
If you wanted to read them as ints you could determine the size with a logarithm function, but that would be overkill.
You could save the numbers as ints, but then you'd have to defer the padding until you printed them later or saved them to a file.
The easiest way to left pad the numbers with zeroes would be to use sprintf() with the correct format specifier to right justify the number. Then you can iterate through each character of the result and replace space e.g. ' ' with '0'. That will create left-side 0-padded entries. E.g. sprintf right justifies your number in a buffer that has room to hold the max sized number you can read, leaving spaces on the left.
Then in a loop indexing one character at a time in the entry, and based on MAX_NUMBER_LEN shown below, you skip extra spaces on the left you don't want zeroes in (e.g. MAX_NUMBER_LEN - maxPaddingLenYouCalculateAtRuntime), and start replacing with zeroes.
Then it's just a matter of creating a buffer whose address you'll pass to sprintf() that has enough space allocated to hold the result. That will have to be as big or bigger than your max length. I would call it maxStrLen rather than e, because naming variables for what they're used for makes for an easier to understand and maintain program.
You have a few choices as to how to allocate that buffer of the right size, including using malloc(). But it is probably easier to determine the maximum size that an integer could be. There's even a C constant that tells you what a 32-bit or 64 bit Integer max. value is, and create an char array of fixed length entries based on that size in advance.
For example:
#define MAX_ENTRIES = 10
#define MAX_NUMBER_LEN = 15
char numbers[MAX_ENTRIES][MAX_NUMBER_LEN]
That would give you the storage to store your sprintf() results in.
Example:
sprintf(numbers[entryNumber], "*right-justifying format specifier you look up*", numberReadFromFile)
Wherein entryNumber is which slot in the array you want to store the result.
The MAX_NUMBER_LEN part you don't need to include when getting the address for sprintf (notice I just passed in numbers[entryNumber], but not the 2nd set of brackets, intentionally). Because by omitting the second set of brackets, you're saying you want the address of the specific [MAX_NUMBER_LEN] chunk corresponding to the entryNumber, inside the numbers array. Note, there is no & on numberReadFromFile either, because you are reading them into a char array as strings, and because you're passing the address of the first char of an array you can just pass the array name. Alternatively you could pass in &numberReadFromFile[0] to get the address of the first element to pass to sprintf().
And when using arrays that way, you don't need the & character to get the variable address to pass to sprintf(), as you would if you were not passing in an array element, because arrays really are simply another notation for pointers in C, and understanding how that works in general is the key to being effective with C in general and worth the initial struggle to comprehend.
Here's an example of how to do the actual zero padding, based on what you got into your array from sprintf. I won't code up a full example because learning C is about the struggle to actually do it yourself. There's no shortcut to real comprehension. I'm giving you the hardest to discover aspects, by you working it through and making a solution of it, you'll gain quite a bit of mastery. This code is off the top of my head, not compiled and tested. It would either work or be close to working.
/* numberToPad is a buffer containing a right-justified number, e.g. a number
* shifted-right by sprintf(), in a buffer sized 15 characters,
* space-padded on the left by sprintf's right-justifying format specifier.
* We want to convert the number to a 10-digit zero-padded number
* inside a 15 character field. The result should be 4 spaces, followed
* by some zeroes, followed by non-zero digits, followed by null-terminator.
* example: "ƀƀƀƀ0000012345\0" where ƀ is a space character.
*/
#define MAX_NUMBER_LEN 15 /* note: 15 includes null-terminator of string */
int maxNumberLenActuallyRead = 10;
int startZeroPaddingPos = MAX_NUMBER_LEN - maxNumberLenActuallyRead
char numberToPad[MAX_NUMBER_LEN];
int i;
for (i = 0; i < MAX_NUMBER_LEN; i++) {
if (i < startZeroPaddingPos)
continue;
if (numberToPad[i] == ' ')
numberToPad[i] = '0';
}

Comparing 2 substrings in C

I having trouble reading a string of characters from a file and then comparing them for the first part of my homework on ubuntu using C.
So the program compiles fine but it seems I get stuck in an infinite loop when it gets to the while loop under the compare string portion of the code. Thanks.
Also, can I get some advice on how to take multiple inputs from the terminal to compare the string from the 'bar' file and the string of x substring of characters after that in the terminal. My output should look like:
% echo "aaab" > bar
% ./p05 bar aa B
2
1
%
This is what I have so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void /*int argc, char *argv[]*/)
{
/******* Open, Read, Close file**********/
FILE *ReadFile;
ReadFile = fopen(/*argv[1]*/"bar", "r");
if(NULL == ReadFile)
{
printf("\n file did not open \n");
return 1;
}
fseek(ReadFile, 0 , SEEK_END);
int size = ftell(ReadFile);
rewind(ReadFile);
char *content = calloc( size +1, 1);
fread(content,1,size,ReadFile);
/*fclose(ReadFile); */
printf("you made it past opening and reading file\n");
printf("your file size is %i\n",size);
/*********************************/
/******String compare and print*****/
int count =0;
const char *tmp = "Helololll";
while (content = strstr(content,"a"))
{
count++;
tmp++;
}
printf("Your count is:%i\n",count);
/***********************************/
return 0;
}
The following loop is infinite if the character 'a' occurs in content.
while (content = strstr(content, "a"))
{
count ++;
tmp ++;
}
It resets content to point to the location of the first occurrence of 'a' on the first iteration. Future iterations will not change the value of content. IOW, content points to "aaab" so the call to strstr will find the first 'a' every time. If you replace tmp++ with content++ inside of your loop, then it will be closer to what you want. I would probably write this with a for loop to make it a little more clear that you are iterating.
char const * const needle = "a";
for (char *haystack=content; haystack=strstr(haystack, needle); haystack++) {
count++;
}
The haystack is incremented so that it always decreases in size. Eventually, you will not find the needle in the haystack and the loop will terminate.

Resources