Can't take input in a dynamically allocated string in c - c

I've been writing a HTML generator in C. After some research I found some code that allows me to take input in a array that allocates more memory to it if you need it. The problem is that after a couple of times, the code stops working.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *inputString(FILE *fp, size_t size);
int main(){
char *nameOfFile;
char *multiF;
int choice;
FILE *f;
printf("Name of file: ");
nameOfFile=inputString(stdin, 10);
f = fopen(strcat(nameOfFile,".html"),"w+");
fprintf(f, "<head>\n");
printf("Title: ");
multiF=inputString(stdin, 10);
fprintf(f, "\t<title>%s</title>\n</head>\n<body>\n", multiF);
while(choice != 99){ //Code stops working in while loop
printf("What do you want to do?\n");
printf("[1]Headings\n");
printf("[2]Paragraphs\n");
printf("[99]Exit\n");
scanf("%d",&choice);
switch(choice){
case 1:
printf("What size[1-6]? ");
scanf("%d",&choice);
if(choice < 7 && choice > 0){
printf("Heading[%d]:",choice);
multiF=inputString(stdin,10);
fprintf(f,"<h%d>%s</h%d>",choice,multiF,choice);
}else{
printf("Input something useful...\n");
}
break;
case 2:
printf("Paragraph: ");
multiF=inputString(stdin,10);
fprintf(f,"<p>%s</p>",multiF);
break;
case 99:
break;
default:
printf("Input something useful...\n");
}
}
fprintf(f,"</body>");
free(multiF);
free(nameOfFile);
return 0;
}
char *inputString(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);
}

This should work:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void inputString(char **str, FILE *fp); // No char *str, because we need to change the value of pointer str
int main(){
char *nameOfFile = malloc(0);
char *multiF = malloc(0); // Calling malloc() for later free()
int choice = 0; // Initialization
FILE *f;
printf("Name of file: ");
inputString(&nameOfFile, stdin);
nameOfFile = realloc(nameOfFile, strlen(nameOfFile) + 5); // You need more memory for ".html"
strcat(nameOfFile, ".html");
f = fopen(nameOfFile, "w");
fprintf(f, "<head>\n");
printf("Title: ");
inputString(&multiF, stdin);
fprintf(f, "\t<title>%s</title>\n</head>\n<body>\n", multiF);
while(choice != 99){
printf("What do you want to do?\n");
printf("[1]Headings\n");
printf("[2]Paragraphs\n");
printf("[99]Exit\n");
scanf(" %d%*c", &choice); // " %d" to discard whitespace characters, and "%*c" to consume '\n'
switch(choice){
case 1:
printf("What size[1-6]? ");
scanf(" %d%*c", &choice);
if(choice < 7 && choice > 0){
printf("Heading[%d]:", choice);
inputString(&multiF, stdin);
fprintf(f, "<h%d>%s</h%d>", choice, multiF, choice);
}else{
printf("Input something useful...\n");
}
break;
case 2:
printf("Paragraph: ");
inputString(&multiF, stdin);
fprintf(f, "<p>%s</p>", multiF);
break;
case 99:
break;
default:
printf("Input something useful...\n");
break;
}
}
fprintf(f, "</body>");
free(multiF);
free(nameOfFile);
fclose(f); // Don't forget to close the file
return 0;
}
void inputString(char **str, FILE *fp){
int ch;
size_t size = 1, index = 0;
free(*str);
*str = malloc(size);
if(!*str)
return;
while(EOF != (ch = fgetc(fp)) && ch != '\n'){
(*str)[index++] = ch;
if(index == size){
*str = realloc(*str, size += 16); // sizeof (char) is guaranteed to be 1 by the standard
if(!*str)
return;
}
}
(*str)[index] = '\0'; // No need to increase index
}
See my comments for the details.
There are some issues in your code:
After scanf("%d",&choice);, a '\n' will be left in stdin. When it is met by inputStrng(), the function stops generating string immediately.
To change the value of a pointer variable in a function, you need to pass a pointer to pointer, such as char **str.
You forgot to close the file, which may cause information loss.

Related

Printing characters with a pointer's function

#include "head.h"
void readText(char *buffer)
{
char c;
int count=0;
char *newBuffer =(char *)calloc(SIZE,sizeof(char));
if(newBuffer==NULL)exit(1);
int i=1;
while ((c = getchar()) != EOF)
{
if (count % SIZE == 0)
{
i++;
newBuffer = (char *)realloc((char *)buffer,i*SIZE);
if(newBuffer==NULL){
printf("Not enought space, bye");
exit(1);
}else{
buffer=newBuffer;
}
}
if (c != '\n'){
*buffer++ = c;
count++;
}
}
}
int main()
{
int choose;
char *buffer;
printf("Please choose the desired method:\n Press 0 for buffer-method.\nPress 1 for Linked List method\n");
scanf("%d", &choose);
buffer = (char *)calloc(SIZE, sizeof(char));
if (buffer == NULL){
printf("Something went wrong, please try again\n");
exit(1);
}
readText(buffer);
printf("%s", buffer);
free(buffer);
return 0;
}
}
So I have been tasked with writing a function, that reads text and each time it passes 60 characters, i need to do realloc. Now everything works till I use called, meaning if I get more then 60 characters from the user, I get an error, and the terminal points to a problem with the realloc.
Whats the problem?

How to fetch a specific substring from string?

In this code, I want to select the second word from the file and the third one also and print that one but I am unable to fetch specific words. I searched a lot and done a lot of stuff to fetch the second and third words from the str variable but unable to do that?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char str[] = "bilal,1000,savings";
char toFind, name[20], account[20];
char * word1;
char * word2;
char * word3;
int i=0, numberOfFields = 3, amount;
static const char * listing[] = {"Name","Amount","Account"};
for(i=0; i<numberOfFields; i++){
printf("%d. Here is your %s \n", i, listing[i]);
}
printf("Which one: ");
scanf("%c", &toFind);
if(toFind == '0'){
printf("selected zero\n");
word1 = strtok(str, ",");
printf("%s\n", word1);
}
else if(toFind == '1'){
printf("selected one\n");
}
else if(toFind == '2'){
printf("selected two\n");
}
return 0;
}
If you parse each line up front, it makes it simpler:
char str[] = "bilal,1000,savings";
char *word1 = strtok(str, ",");
char *word2 = strtok(NULL, ",");
char *word3 = strtok(NULL, ",");
printf("Which one: ");
scanf("%c", &toFind);
if(toFind == '0'){
printf("selected zero\n");
printf("%s\n", word1);
}
else if(toFind == '1'){
printf("selected one\n");
printf("%s\n", word2);
}
else if(toFind == '2'){
printf("selected two\n");
printf("%s\n", word3);
}

how to stop a while loop to enter, in the same variable

I have to enter random names and weights and finish the loop when I hit enter instead of the name. However the way I used to detect the enter does not serve to take the name so getting two variables. The question is how to put the enter of the test and name using the same variable
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
int c, weight[1000], i = 0;
char name[1000];
puts ("Enter the person's name or only enter to end the program");
if ((c = getchar() == '\n')) {
} else {
while (c != '\n') {
printf("Enter the name");
scanf("%s", &nome[i]);
i++;
printf("Enter the \n");
scanf("%i", &weight[i]);
}
}
return 0;
}
Here is a simple example
#include <stdio.h>
#include <string.h>
int main(void)
{
char name[1000] = {0}; // initialise
puts ("Enter the person's name or only enter to end the program");
if (fgets(name, sizeof(name), stdin) != NULL) {
name [ strcspn(name, "\r\n") ] = 0; // remove trailing newline etc
if (strlen(name)) {
printf("The name entered was: %s\n", name);
}
else {
printf("You did not enter a name\n");
}
}
return 0;
}
First off, names is an array of characters and you're treating it like an array of strings. Secondly, loops that need to exit based on input are most clearly expressed with break:
char *names[1000];
int count = 0;
while (1) {
char *r, buf[1000];
int len;
char *r = fgets(buf, 1000, stdin);
if (NULL == r) break; // EOF
if ((len = strlen(buf)) < 2) break; // NL only
r = malloc(len + 1);
if (NULL == r) break;
strcpy(r, buf);
names[count] = r;
count += 1;
...
}
...

while loop terminating before it is supposed to C

This program is supposed to copy an existing txt file to a new txt code file. However is isn't working right. For some reason it always stops after the third iteration.
Suggestions?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char fileNameIn[100];
char fileNameOut[100];
FILE *ptrIn = NULL; //____ File Pointers
FILE *ptrOut = NULL;
char str[1000]; //this is used at fgets and it obtains sentences
/*_________________Counter variables)*/
char *token;
int ctr = 0;
int ndel = -1;
char wordA[10];
char sentence[101];
char del[10] = " !-,.";
;
int temp = 0;
printf("Enter the input filename: \n");
// gets(fileNameIn);
scanf("%s", fileNameIn);
//printf("You entered: %s\n",fileNameIn);
printf("Enter the output filename: \n");
scanf("%s", fileNameOut);
ptrIn = fopen(fileNameIn, "r"); // r is to read
ptrOut = fopen(fileNameOut, "w"); //w is to write on file
if (ptrIn == NULL || ptrOut == NULL) {
printf("Unable to open file\n");
exit(1);
}
//while(fgets (str,sizeof(str), ptrIn) )
while (fgets(str, sizeof(str), ptrIn)) { // while we are not at the end of the file
puts(str);
// if(temp==0)
// {
token = strtok(str, del);
temp = -1;
printf(
"Enter position of word to delete (Start counting at 0). Enter -1 to skip deletion:\n");
scanf("%d", &ndel);
printf("You selected: %d\n", ndel);
while (token != NULL) // while loop inside a sentence
{
if (ctr != ndel) {
strcpy(wordA, token);
}
token = strtok(NULL, del);
if (ctr != ndel) {
strcat(sentence, wordA);
strcat(sentence, " ");
printf("halfway?");
}
ctr++;
} // endof sentence loop
fprintf(ptrOut, "%s", sentence);
printf("the sentence is now:\n%s", sentence);
printf("___________________________________________");
printf("\n");
strcpy(sentence, "");
ctr = 0;
ndel = -1;
} //end of while loop eof
printf("Finish the main: ");
fflush(ptrOut);
fclose(ptrIn);
fclose(ptrOut);
return EXIT_SUCCESS;
}
This is an example of the existing file:
test.txt:
hello my name is john.
this is a test.
after the third line the while
loop stops
this does the get copied
You strcat() to senetence wihtout initializing it, strcat() will search for the terminating nul byte of it's first argument and start copying characters from it's second argument start from that position, so a simple
sentence[0] = '\0';
right after the outer while loop will fix it, but your code needs reformatting and you should make it safer by checking every single potential undefined behavior cause.
This is the code and it now works correctly
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char fileNameIn[100] = {0};
char fileNameOut[100] = {0};
FILE *ptrIn = NULL;
FILE *ptrOut = NULL;
char str[1024] = {0};
char *token = NULL;
int ctr = 0;
int ndel = -1;
char wordA[1024] = {0};
char sentence[1024] = {0};
char del[] = " !-,.";
int temp = 0;
printf("Enter the input filename > ");
fflush(stdout);
scanf("%99s", fileNameIn);
printf("Enter the output filename > ");
fflush(stdout);
scanf("%99s", fileNameOut);
ptrIn = fopen(fileNameIn, "r"); // r is to read
if (ptrIn == NULL)
{
printf("Unable to open file %s\n", fileNameIn);
return -1;
}
ptrOut = fopen(fileNameOut, "w"); // w is to write on file
if (ptrOut == NULL)
{
fclose(ptrIn);
printf("Unable to open file %s\n", fileNameOut);
return -1;
}
while (fgets(str, sizeof(str), ptrIn)) // while we are not at the end of the file
{
puts(str);
token = strtok(str, del);
temp = -1;
printf("Enter position of word to delete (Start counting at 0) `-1 to skip deletion' > ");
if (scanf("%d", &ndel) != 1)
continue;
printf("You selected: %d\n", ndel);
sentence[0] = '\0';
while (token != NULL)
{
if (ctr != ndel)
strcpy(wordA, token);
token = strtok(NULL, del);
if (ctr != ndel)
{
strcat(sentence, wordA);
strcat(sentence, " ");
}
ctr++;
}
fprintf(ptrOut, "%s", sentence);
printf("the sentence is now:\n%s", sentence);
printf("\n");
ctr = 0;
ndel = -1;
}
printf("Finish the main: ");
fflush(ptrOut);
fclose(ptrIn);
fclose(ptrOut);
return EXIT_SUCCESS;
}

(C code) how would I pass my global variables between functions and return them when the main function needs them also?

(C code) how would I pass my global variables between functions and return them when the main function needs them also? I've posted my code below for reference. Of course, I also have a header file with my function prototypes in it as well but they only list variable types inside the closed brackets, not the variable names...
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "myheader.h"
char user_filename[150];
char user_filename2[150];
FILE *fp;
FILE *fp2;
int num_shift;
int main()
{
int choice; // main variables
int option;
char result;
char ch;
int offset;
char character;
int tmp;
option = 0;
num_shift = 0;
strncpy(user_filename, "not set", sizeof("not set"));
strncpy(user_filename2, "not set", sizeof("not set"));
fp = NULL;
fp2 = NULL;
choice = menu(num_shift, user_filename, option); // get user's first selection
while(choice != QUIT) //execute so long as choice is not equal to QUIT
{
switch(choice)
{
case INPUT_FILE:
input(user_filename);
break;
case OUTPUT_FILE:
output();
break;
case NUM_TO_SHIFT:
num_shift = shift(num_shift);
printf ("Shift by %d\n",num_shift);
break;
case ENCODE:
encode(result, ch, num_shift, character);
break;
case QUIT:
quit();
break;
case REVIEW:
review (user_filename);
break;
default:
printf("Oops! An invalid choice slipped through. ");
printf("Please try again.\n");
}
choice = menu(num_shift, user_filename, 0); /* get user's subsequent selections */
}
quit();
}
int menu(int num_shift, char * user_filename, int option)
{
printf("\nText Encoder Service\n\n");
printf("1.\tEnter name of input file (currently '%s')\n", user_filename);
printf("2.\tEnter name of output file (currently '%s')\n", user_filename2);
printf("3.\tEnter number of characters data should be shifted (currently %d)\n", num_shift);
printf("4.\tEncode the text\n");
printf("5.\tReview the text in the input file\n");
printf("\n0.\tQuit\n\n");
printf("Make your selection: \n");
while( (scanf(" %d", &option) != 1) /* non-numeric input */
|| (option < 0) /* number too small */
|| (option > 5)) /* number too large */
{
fflush(stdin); /* clear bad data from buffer */
printf("That selection isn't valid. Please try again.\n\n");
printf("Your choice? ");
}
printf("Selecting %d\n\n", option);
return option;
}
int input(char * user_filename)
{
printf("Enter the filename of the file to encode:\n");
printf("(hit the Enter key when done)\n");
scanf("%s", user_filename);
printf("Getting %s\n\n", user_filename);
fp = fopen (user_filename, "r");
if (fp == NULL)
{
printf("\nSorry, I'm unable to open the file (%s) for reading\n", user_filename);
printf("Please try again.\n");
}
else
{
fclose(fp);
}
return INPUT_FILE;
}
int output()
{
printf("Enter the filename of the output file to store encoded information:\n");
printf("(hit the Enter key when done)\n");
scanf("%s", user_filename2);
printf("Opening File for Writing %s\n\n", user_filename2);
fp2 = fopen (user_filename2, "w");
if (fp2 == NULL)
{
printf("\nSorry, I'm unable to open the file (%s) for writing\n", user_filename2);
printf("Please try again.\n");
} else
{
fclose(fp2);
}
//return user_filename;
return INPUT_FILE;
}
int shift(int num_shift)
{
printf("Enter the number of letters to shift for each character: \n");
printf("(hit the Enter key when done)\n");
scanf("%d", &num_shift);
printf("Setting shift value to: %d\n\n", num_shift);
return num_shift;
}
int encode(char result, char ch, int offset, char character2)
{
int character;
printf("starting encoding with offset of %d\n", offset);
fp = fopen(user_filename, "r");
fp2 = fopen(user_filename2, "w+bc");
if ((fp == NULL) || (fp2 == NULL))
{
printf ("File not found\n");
return (0);
}
fseek(fp, 0, SEEK_SET);
printf("staring Encoding from %s to %s at position %ld\n", user_filename, user_filename2, ftell(fp));
int i = 0;
while(character = fgetc(fp))
{
if ( character == EOF)
{
//printf("%c",character);
//fprintf(fp2,"%c",result);
fclose(fp);
fflush(fp2);
fclose(fp2);
return(0);
}
if (isalpha (character))
{
if (character >= 'a' && character <= 'z')
{
result = character - 'a';
result = (result + offset) % 26; // 26 letters in the alphabet
result += 'a';
if (result < 'a')
{
result = 'z' - ('a' - result)+1;
}
} else if (character >= 'A' && character <= 'Z')
{
result = character - 'A';
result = (result + offset) % 26; // 26 letters in the alphabet
result += 'A';
if (result < 'A')
{
result = 'Z' - ('A' - result)+1;
}
}
//printf("(%c)",result);
} else
{
result = character;
//printf("(%x)", result);
}
printf("%c",result);
fprintf(fp2,"%c",result);
}
return 0;
}
void quit()
{
//fclose(fp);
//fclose(fp2);
printf("Quiting...Bye!");
printf("\n");
exit(0);
}
int review(char * user_filename)
{
char character;
fp = fopen(user_filename, "r");
printf("Showing text from %s file\n", user_filename);
printf("----------BEGIN OF TEXT--------------\n");
while(character = fgetc(fp))
{
if ( character == EOF)
{
printf("%c",character);
printf("\n----------END OF TEXT--------------\n");
fclose(fp);
return(0);
}
printf("%c",character);
}
}
You don't need to pass them around as parameters, you can just access them from anywhere (hence global, well as long as you can see the variable).
Any modifications made to those variables are visible to everyone (aside from multithreading issues) so you have no trouble using them in your functions and in main as well.
You do not need to pass global variables because global variables have global scope, that is they can be accessed anywhere. This is VERY BAD programming practice because it may introduce side-effects later in the program when you decide to use the same name for another purpose for example.
See wikipedia for details.

Resources