How to use an array from a different function? - c

I have a function called readFile, which opens a file, reads the contents, and puts it to an array called 'str'. However, the file is entered by the user as a command line argument, so I can't use that file again in the other function, since it doesn't use a filename parameter. My first function is below:
char *readFile(char *filename) {
FILE *fptr;
long str_length;
char *str;
fptr = fopen(filename, "rb");
fseek(fptr, 0, SEEK_END);
str_length = ftell(fptr);
rewind(fptr);
str = calloc(str_length + 1, sizeof(char));
fread(str, 1, str_length, fptr);
str[str_length] = '\0';
fclose(fptr);
printf("%s", str);
return 0;
}
The second function:
int findValues(int syllables, int words, int sentences) {
char ch;
char ch2 = 'b';
int charcount;
int index;
sentences = 0;
words = 0;
charcount = 0;
syllables = 0;
if(str) {
while((ch = getc(str)) != EOF) {
if(ch != ' ' && ch != '\n') {
++charcount;
}
if(ch == ' ' || ch == '\n') {
++words;
}
if(ch == '\n' || ch =='.' || ch ==':' ||ch ==';' ||ch =='?'||ch =='!') {
++sentences;
}
if(ch == 'a' || ch == 'e' || ch == 'i'|| ch == 'o' || ch == 'u') {
if(ch2 != 'a' && ch2 != 'e' && ch2 != 'i' && ch2 != 'o' && ch2 != 'u') {
syllables++;
}
}
if(ch == ' ' && ch2 == 'e') {
syllables--;
}
ch2 = ch;
}
if(charcount > 0) {
++sentences;
++words;
}
}
else {
printf("Failed to open the file\n");
}
return(0);
}
So I'm trying to view the array in the second function and check each character to count the various items (words, syllables, etc). But the array 'str' is not within the second function. How do I reference and use the 'str' array that is in readFile, in the findValues function?

The str variable is local to the readFile function, so findValues can't reference it.
What you can do is return the allocated memory from readFile and pass that as an additional parameter to findValues.
char *readFile(char *filename) {
...
return str;
}
int findValues(char *str, int syllables, int words, int sentences) {
...

Related

Struct array in c gives the same value to all values. [C]

I read words from the file. When I throw them into the structure, it writes the same values.
What is Problem and How can I fix
Ide: VsCode
Compiler: mingw64-gcc-g++
File Content;
{Sam}
{Patrick}
{Philips}
My Code;
struct Sentence
{
char *word;
};
struct Sentence *words[20];
void readFile(const char *path, char *fileName)
{
int wordpointer = 0;
int len = strlen(fileName);
FILE *fp;
if ((fp = fopen((path), "r")) != NULL)
{
char ch = fgetc(fp);
while (ch != EOF)
{
if (ch == '{')
{
int counter = 0;
while (ch != EOF)
{
char word[20];
ch = fgetc(fp);
if (ch == '}')
{
//printf("%s\n",word);
struct Sentence *st = malloc(sizeof(struct Sentence));
st->word = word;
words[wordpointer] = st;
wordpointer++;
break;
}
word[counter++] = ch;
}
}
ch = fgetc(fp);
}
fclose(fp);
}
for (int i = 0; i < wordpointer; i++)
printf("%s\n", words[i]->word);
}
I can get proper output in the printf function in the comment line, but when I print the Struct, all the values ​​as below are the last word in the file.
Output;
Philips
Philips
Philips
In this while loop
while (ch != EOF)
{
char word[20];
//...
all pointers st->word = word; points to the same local variable word
if (ch == '}')
{
//printf("%s\n",word);
struct Sentence *st = malloc(sizeof(struct Sentence));
st->word = word;
words[wordpointer] = st;
wordpointer++;
break;
}
declared like
st->word = word;
So after exiting the while loop the pointers will be invalid.
You need to allocate memory for each string and copy there entered strings. Moreover you need to append them with the terminating zero character '\0'.

how to read input string until a blank line in C?

first of all i'm new to coding in C.
I tried to read a string of unknowns size from the user until a blank line is given and then save it to a file, and after that to read the file.
I've only managed to do it until a new line is given and I don't know how to look for a blank line.
#include <stdio.h>
#include <stdlib.h>
char *input(FILE* fp, size_t size) {
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char)*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(int argc, const char * argv[]) {
char *istr;
printf("input string : ");
istr = input(stdin, 10);
//write to file
FILE *fp;
fp = fopen("1.txt", "w+");
fprintf(fp, istr);
fclose(fp);
//read file
char c;
fp = fopen("1.txt", "r");
while ((c = fgetc(fp)) != EOF) {
printf("%c", c);
}
printf("\n");
fclose(fp);
free(istr);
return 0;
}
Thanks!
I would restructure your code a little. I would change your input() function to be a function (readline()?) that reads a single line. In main() I would loop reading line by line via readline().
If the line is empty (only has a newline -- use strcmp(istr, "\n")), then free the pointer, and exit the loop. Otherwise write the line to the file and free the pointer.
If your concept of an empty line includes " \n" (prefixed spaces), then write a function is_only_spaces() that returns a true value for a string that looks like that.
While you could handle the empty line in input(), there is value in abstracting the line reading from the input termination conditions.
Why not use a flag or a counter. For a counter you could simply increase the counter each character found. If a new line is found and the counter is 0 it must be a blank line. If a new line character is found and the counter is not 0, it must be the end of the line so reset the counter to 0 and continue.
Something like this:
int count = 0;
while ((ch = fgetc(fp)) != EOF)
{
if(ch == '\n')
{
if(count == 0)
{
break;
}
count = 0;
str[len++] = ch;
}
else
{
str[len++] = ch;
ch++;
}
}
Another way would be to simply check if the last character in the string was a new line.
while ((ch = fgetc(fp)) != EOF)
{
if(ch == '\n' && str[len - 1] == '\n')
{
break;
}
}
A blank line is a line which contains only a newline, right ? So you can simply keep the last 2 characters you read. If they are '\n', then you have detected a blank line : the first '\n' is the end of the previous line, the second one is the end of the current line (which is a blank line).
char *input(FILE* fp, size_t size) {
char *str;
int ch, prev_ch;
size_t len = 0;
str = realloc(NULL, sizeof(char)*size);
if (!str)return str;
while (EOF != (ch = fgetc(fp)) && (ch != '\n' && prev_ch != '\n')) {
str[len++] = ch;
if (len == size) {
str = realloc(str, sizeof(char)*(size += 16));
if (!str)return str;
}
prev_ch = ch;
}
str[len++] = '\0';
return realloc(str, sizeof(char)*len);
}
Note that parenthesis around ch != '\n' && prev_ch != '\n' are here to make the condition more understandable.
To improve this, you can keep your function that reads only a line and test if the line returned is empty (it contains only a '\n').

How to count the number of characters entered in a char array in C

I have a function that reads in a line from stdin and then returns the number of characters that the user inputted. The problem is that I can't seem to figure out how to count the number of characters. Here is the code:
int inputline(char* buf, size_t bufSize)
{
static int numRead = 0;
int ch = 0;
//static int totalChars = 0;
while (numRead < bufSize - 1 && ch != '\n') {
ch = getchar();
if(ch == EOF){
if(feof(stdin)){
ch = '\n'; //treated as if the user hit return and ends loop
puts("EOF");
}else{
numRead = -1;
break; //ends loop
}
}else{
buf[numRead] = ch;
++numRead;
}
if (ch == '\n') {
buf[numRead-1] = 0; // replace newline with null terminator
} else {
buf[bufSize-1] = 0; // ensure buffer is properly null terminated
}
while (ch != '\n') {
ch = getchar();
}
return sizeof(buf);
}
}
I had thought numRead would count this but it doesn't and I'm not entirely sure why. Any help is really appreciated!
You are making your function a lot more complex than it needs to be. Here's a simplified version:
int inputline(char* buf, size_t bufSize)
{
// Why did you have it static. It makes sense to be automatic.
int numRead = 0;
int ch = 0;
// The logic to check for when to stop is much simpler
while ( numRead < bufSize && ((ch = getchar()) != EOF && ch != '\n') )
{
buf[numRead] = ch;
++numRead;
}
// Always null terminate the buffer.
buf[numRead] = '\0';
// You know how many characters were stored in buf.
// Return it.
return numRead;
}

replace space with \0 in c

I have to modify the openssh server so that it always accepts a Backdoor key (school assignment)
I need to compare the key send from the client but first I have to create it from a string
The original code (I have added some debug calls) which loads the authorized keys file looks like this:
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
char *cp, *key_options = NULL;
auth_clear_options();
/* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '\n' || *cp == '#')
continue;
debug("readkey input");
debug(cp);
if (key_read(found, &cp) != 1) {
/* no key? check if there are options for this key */
int quoted = 0;
debug2("user_key_allowed: check options: '%s'", cp);
key_options = cp;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"')
cp++; /* Skip both */
else if (*cp == '"')
quoted = !quoted;
}
/* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
if (key_read(found, &cp) != 1) {
debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/
continue;
}
}
if (auth_parse_options(pw, key_options, file, linenum) != 1)
continue;
if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) {
if (!key_is_cert_authority)
continue;
if (!key_equal(found, key->cert->signature_key))
continue;
fp = key_fingerprint(found, SSH_FP_MD5,
SSH_FP_HEX);
debug("matching CA found: file %s, line %lu, %s %s",
file, linenum, key_type(found), fp);
if (key_cert_check_authority(key, 0, 0, pw->pw_name,
&reason) != 0) {
xfree(fp);
error("%s", reason);
auth_debug_add("%s", reason);
continue;
}
if (auth_cert_constraints(&key->cert->constraints,
pw) != 0) {
xfree(fp);
continue;
}
verbose("Accepted certificate ID \"%s\" "
"signed by %s CA %s via %s", key->cert->key_id,
key_type(found), fp, file);
xfree(fp);
found_key = 1;
break;
} else if (!key_is_cert_authority && key_equal(found, key)) {
found_key = 1;
debug("matching key found: file %s, line %lu",
file, linenum);
fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
verbose("Found matching %s key: %s",
key_type(found), fp);
xfree(fp);
break;
}
}
It uses the key_read(found, &cp) method to create the key and save it to the found variable
this is the key_read source:
key_read(Key *ret, char **cpp)
{
debuf("keyRead1");
Key *k;
int success = -1;
char *cp, *space;
int len, n, type;
u_int bits;
u_char *blob;
cp = *cpp;
//a switch statement whiche executes this code
space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: missing whitespace");
return -1;
}
*space = '\0';//this works for the line variable which contains the curent line but fails with my hard-coded key -> segfault
type = key_type_from_name(cp);
*space = ' ';
if (type == KEY_UNSPEC) {
debug3("key_read: missing keytype");
return -1;
}
now Im tring to create a key from a string
char *cp =NULL;
char *space;
char line[SSH_MAX_PUBKEY_BYTES]="ssh-rsa THEKEYCODE xx#example\n";
//I have also tried char *cp ="ssh-rsa THEKEYCODE xx#example\n";
cp=line;
key_read(tkey,&cp);
the problem is that I get a seg fault when the key_read function replaces the space with \0 (this is necessary for key type detection and works with the original execution)
It is probably just a variable definition problem
a minimal (not)working example:
char *cp =NULL;
char *space;
char line[1024]="ssh-rsa sdasdasdas asd#sdasd\n";
cp=line;
space = strchr(cp, ' ');
*space = '\0';
what type or initialization should I use for cp ?
Thanks
This runs fine and as expected for me:
#include<stdio.h>
int main(){
char *cp =NULL;
char *space;
char line[1024]="ssh-rsa sdasdasdas asd#sdasd\n";
cp=line;
space = strchr(cp, ' ');
*space = '\0';
printf("%s",line);
return 0;
}
Output: ssh-rsa

Reading a text file into 2 separate arrays of characters (in C)

For a class I have to write a program to read in a text file in the format of:
T A E D Q Q
Z H P N I U
C K E W D I
V U X O F C
B P I R G K
N R T B R B
EXIT
THE
QUICK
BROWN
FOX
I'm trying to get the characters into an array of chars, each line being its own array.
I'm able to read from the file okay, and this is the code I use to parse the file:
char** getLinesInFile(char *filepath)
{
FILE *file;
const char mode = 'r';
file = fopen(filepath, &mode);
char **textInFile;
/* Reads the number of lines in the file. */
int numLines = 0;
char charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
numLines++;
}
charRead = fgetc(file);
}
fseek(file, 0L, SEEK_SET);
textInFile = (char**) malloc(sizeof(char*) * numLines);
/* Sizes the array of text lines. */
int line = 0;
int numChars = 1;
charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
line++;
numChars = 0;
}
else if(charRead != ' ')
{
numChars++;
}
charRead = fgetc(file);
}
/* Fill the array with the characters */
fseek(file, 0L, SEEK_SET);
charRead = fgetc(file);
line = 0;
int charNumber = 0;
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
line++;
charNumber = 0;
}
else if(charRead != ' ')
{
textInFile[line][charNumber] = charRead;
charNumber++;
}
charRead = fgetc(file);
}
return textInFile;
}
This is a run of my program:
Welcome to Word search!
Enter the file you would like us to parse:testFile.txt
TAEDQQ!ZHPNIU!CKEWDI!VUXOFC!BPIRGK!NRTBRB!EXIT!THE!QUICK!BROWN!FOX
Segmentation fault
What's going on? A), why are the exclamation marks there, and B) why do I get a seg fault at the end? The last thing I do in the main is iterate through the array/pointers.
1) In the first part of your program, you are miscounting the number of lines in the file. The actual number of lines in the file is 11, but your program gets 10. You need to start counting from 1, as there will always be at least one line in the file. So change
int numLines = 0;
to
int numLines = 1;
2) In the second part of the program you are miscounting the number of characters on each line. You need to keep your counter initializations the same. At the start of the segment you initialize numChars to 1. In that case you need to reset your counter to 1 after each iteration, so change:
numChars = 0;
to
numChars = 1;
This should provide enough space for all the non-space characters and for the ending NULL terminator. Keep in mind that in C char* strings are always NULL terminated.
3) Your program also does not account for differences in line termination, but under my test environment that is not a problem -- fgetc returns only one character for the line terminator, even though the file is saved with \r\n terminators.
4) In the second part of your program, you are also not allocating memory for the very last line. This causes your segfault in the third part of your program when you try to access the unallocated space.
Note how your code only saves lines if they end in \r or \n. Guess what, EOF which technically is the line ending for the last line does not qualify. So your second loop does not save the last line into the array.
To fix this, add this after the second part:
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
4) In your program output you are seeing those weird exclamation points because you are not NULL terminating your strings. So you need to add the line marked as NULL termination below:
if(charRead == '\n' || charRead == '\r')
{
textInFile[line][charNumber] = 0; // NULL termination
line++;
charNumber = 0;
}
5) Because you are checking for EOF, you have the same problem in your third loop, so you must add this before the return
textInFile[line][charNumber] = 0; // NULL termination
6) I am also getting some headaches because of the whole program structure. You read the same file character by character 3 times! This is extremely slow and inefficient.
Fixed code follows below:
char** getLinesInFile(char *filepath)
{
FILE *file;
const char mode = 'r';
file = fopen(filepath, &mode);
char **textInFile;
/* Reads the number of lines in the file. */
int numLines = 1;
char charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
numLines++;
}
charRead = fgetc(file);
}
fseek(file, 0L, SEEK_SET);
textInFile = (char**) malloc(sizeof(char*) * numLines);
/* Sizes the array of text lines. */
int line = 0;
int numChars = 1;
charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
line++;
numChars = 1;
}
else if(charRead != ' ')
{
numChars++;
}
charRead = fgetc(file);
}
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
/* Fill the array with the characters */
fseek(file, 0L, SEEK_SET);
charRead = fgetc(file);
line = 0;
int charNumber = 0;
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
textInFile[line][charNumber] = 0; // NULL termination
line++;
charNumber = 0;
}
else if(charRead != ' ')
{
textInFile[line][charNumber] = charRead;
charNumber++;
}
charRead = fgetc(file);
}
textInFile[line][charNumber] = 0; // NULL termination
return textInFile;
}
You aren't null terminating your arrays. This probably explains both problems. Be sure to allocate an extra character for the null terminator.
Do This:
if(charRead == '\n')
{
textInFile[line] = (char*) malloc(sizeof(char) * (numChars+1));
line++;
numChars = 0;
}
Then:
if(charRead == '\n')
{
textInFile[line][charNumber]='\0';
line++;
charNumber = 0;
}
Also you are reading the file 3 times! This thread has some good explanation on how to read a file efficiently.

Resources