reading and saving known number of lines of unknown lengths of strings - c

I want to receive the number of lines of input from the user then read and save the lines of unknown lengths in an array.
I know that the way I am saving the lines is wrong but I don't know how to correct it.
int nos; // number of strings
scanf_s("%d", &nos);
char** strs = malloc(nos * sizeof(char*)); // array of strings
for (int i = 0; i < nos; i++) // receiving strings
{
scanf_s("%s", (strs+i));
}

You're close, but you're forgetting to allocate memory for the string. If you're working with POSIX-compliant systems (i.e. pretty much everything except Windows) then use the %ms scanf() format specifier to allocate the buffer for the string as you're reading it (note that this stops after whitespace):
scanf("%ms", &strs[i]);
For Windows, implement a gets()-like function:
#include <stdlib.h>
#include <stdio.h>
int msgets(char **str)
{
int ch = 0;
size_t len = 0;
while(ch != '\n')
{
len++;
*str = realloc(*str, len);
ch = getchar();
(*str)[len-1] = ch;
}
(*str)[--len] = 0;
return len;
}
Here's how to use it in replacement of the scanf() line:
msgets(&strs[i]);
Other than that, your code looks fine.
Here's an almost complete example with my code included:
#include <stdlib.h>
#include <stdio.h>
int msgets(char **str)
{
int ch = 0;
size_t len = 0;
while(ch != '\n')
{
len++;
*str = realloc(*str, len);
ch = getchar();
(*str)[len-1] = ch;
}
(*str)[--len] = 0;
return len;
}
int main(void)
{
int nos; // number of strings
scanf("%d ", &nos);
char** strs = malloc(nos * sizeof(char*)); // array of strings
for (int i = 0; i < nos; i++) // receiving strings
{
msgets(&strs[i]);
}
/* Do something with strs[] here */
return 0;
}

if you read carefully this answerHow can I read an input string of unknown length? , and modify your code it should be something like this.
I also add a print for loop to see the results of this code
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE* fp, size_t size){
char *str=NULL;
int ch;
size_t len = 0;
str = realloc(str, sizeof(char)*size);
if(!str){
printf("[DEBUG]\n");
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);
}
void empty_stdin (void) /* simple helper-function to empty stdin */
{
char c;
while ((c = getchar()) != '\n' && c != EOF);
return;
}
int main(void){
int nos,i; /*number of strings*/
scanf("%d", &nos);
empty_stdin();
char ** strs = malloc(nos * sizeof(char*)); /*array of strings*/
for (i = 0; i < nos; i++) {/*receiving strings*/
*(strs+i) = inputString(stdin,1);
}
for(i=0;i<nos;i++){
printf("%s\n",*(strs+i));
}
return 0;
}
input:
3
123456789
foo
hello world
output:
123456789
foo
hello world

Related

Dynamic memory allocation for an array of pointers to char in C

I'm building a word counter program. To achieve this, I was thinking about saving the string the user inputted, and using strtok() to split the sentence with space as the delimiter. But first I want to allocate enough memory for each word. Let's say the sentence is "Hello World". I've already dynamically allocated memory for the string itself. Now I want to split Hello World into 2 strings, "Hello" and "World". My goal is to allocate enough memory so that there's not too much empty space but I also don't want to allocate too little space. Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
char *strmalloc(char **string);
char *user_input = NULL;
char *word_array[];
int main(void) {
printf("Enter a sentence to find out the number of words: ");
user_input = strmalloc(&user_input);
return 0;
}
char *strmalloc(char **string) {
char *tmp = NULL;
size_t size = 0, index = 0;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
if (size <= index) {
size += 1;
tmp = realloc(*string, size);
if (!tmp) {
free(*string);
string = NULL;
break;
}
*string = tmp;
}
(*string)[index++] = ch;
}
return *string;
}
How would I go about doing this? Should I do the splitting first or allocate the space required for the array first?
You can count words without splitting the sentence, here is an example :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
// Change this to change the separator characters
static inline char isSeparator(char ch) { return isspace(ch) || ispunct(ch); }
char * jumpSeparator(char *string) {
while(string[0] && isSeparator(string[0])) string++;
return string;
}
char * findEndOfWord(char *string) {
while (string[0] && !isSeparator(string[0])) string++;
return string;
}
int countWords(char *string) {
char * ptr = jumpSeparator(string);
if (strlen(ptr) == 0) return 0;
int count = 1;
while((ptr = findEndOfWord(ptr)) && ptr[0]) {
ptr = jumpSeparator(ptr);
if (!ptr) break;
count++;
}
return count;
}
int main() {
char * sentence = "This is,a function... to||count words";
int count = countWords(sentence);
printf("%d\n", count); //====> 7
}
EDIT : Reusing the same functions here is another example that allocates substrings dynamically :
int main() {
char * sentence = "This is,a function... to||split words";
int count = countWords(sentence);
char * ptr = sentence, *start, *end;
char ** substrings = malloc(count * sizeof(char *));
int i=0;
while((ptr = jumpSeparator(ptr)) && ptr[0]) {
start = ptr;
ptr = findEndOfWord(ptr);
end = ptr;
int len = end-start;
char * newString = malloc(len + 1);
memcpy(newString, start, len);
newString[len] = 0;
substrings[i++] = newString;
}
// Prints the result
for(int i=0; i<count; i++) printf("%s\n", substrings[i]);
// Frees the allocated memory
for(int i=0; i<count; i++) free(substrings[i]);
free(substrings);
return 0;
}
Output :
This
is
a
function
to
split
words

Reading Multiple lines in C

So I am trying to read input from a text file and print the exact same thing I read in C.So this below is the input followed by enter:
input: Hi
output: Hi
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE *fp, size_t size) {
//The size is extended by the input with the value of the provisional
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char) * size); //size is start 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(void) {
char *m;
// printf("input string : ");
m = inputString(stdin, 10);
printf("%s\n", m);
free(m);
return 0;
}
For this input:
Hi, this is the first line
This is the second line
This is the third line \n
This is the output I expected:
Hi, this is the first line
This is the second line
This is the third line \n
This is what I got:
Hi, this is the first line
It makes sense that the code is printing only the first line, but since the condition in the guard will no longer be true after hitting the new line, but I don't know how to structure my code so it reads line by line and prints them respectively.
If you want the code to read each line, remove && ch != '\n' from the condition of the while loop.
Also, the code is reading from stdin instead of a file. Use fopen to read from a file, i.e. m = inputString(fopen("filename.txt", "r"), 512).
Try this,
#include<stdio.h>
void main(int argc, char **argv)
{
int cnt=0;
char buf[1024];
FILE *fptr=stdin;
printf("Input: \n");
char ch=fgetc(fptr);
buf[cnt++]=ch;
while(ch!='$')
{
buf[cnt++]=ch;
ch=fgetc(fptr);
}
buf[cnt++]='$';
buf[cnt]='\0';
printf("Output:\n");
fputs(buf,stdout);
fclose(fptr);
}
I have put '$' as the delimiter.
I have used an extra buffer as newline is bound to EOF for stdin. So if I print out the character immediately it comes out of loop.
All you need is repeat the process as long as you can read lines:
int main(void) {
char *m;
// printf("input strings: ");
while ((m = inputString(stdin, 10)) != NULL) {
printf("%s\n", m);
free(m);
}
return 0;
}
For this to work correctly, you must return NULL at end of file:
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE *fp, size_t size) {
//The size is extended by the input with the value of the provisional
int ch;
size_t len = 0;
char *str = malloc(size);
if (str == NULL)
return NULL;
while ((ch = fgetc(fp)) != EOF && c != '\n') {
if (len + 2 > size) {
char *new_str = realloc(str, size += 16);
if (!new_str) {
free(str);
return NULL;
str = new_str;
}
str[len++] = ch;
}
if (c == EOF && len == 0) {
/* at end of file */
free(str);
return NULL;
}
str[len++] = '\0';
return realloc(str, len);
}
Instead of:
while(EOF!=(ch=fgetc(fp))&& ch != '\n' ){
// stuff
}
you could do:
while(EOF!=(ch=fgetc(fp))){
// stuff
if (ch == '\n') break;
}
Now you have consumed the newline.

caesar encryption in C with undefined input

iam trying to write a simple caesar program in C.
The input i want to give should be with undefined lenght like in the program.
The problem i have is, when i enter a short string like "HELLO WORLD" in the encrypted string i have some random additions at the end.
When i give a longer string as input the program crashes befor it starts to encrypt.
I have no idea where the problem could be, maybe some of you can give me a hand or have ideas what is crap here :/
Every advice is welcome thank you :)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// realloc the size of memory for the user input
char *inputString(FILE *fp, size_t size)
{
// the size is extendet by the input with the value of the provisional
char *str;
int ch = 0;
size_t len = 0;
str = realloc(NULL, sizeof(char)*size); // size is start 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);
}
// lowercase letters
void makeLowerCase(char *input)
{
while(*input != '\0') // "while(*input)" would also work
{
*input = tolower(*input);
input++;
}
}
// test function
// character length of the input
int lengthOfInput(char *input)
{
int len = 0;
while(*input != '\0') // "while(*input)" would also work
{
len++;
input++;
}
return len;
}
// encrypts the input caesar
char *encrypt(char *toBeEncrypted, int caesarNum)
{
int tmp = 0; // going through the input
char *tbE;
for(;*toBeEncrypted != '\0'; toBeEncrypted++, tmp++)
{
*(tbE+tmp) = *toBeEncrypted + caesarNum;
printf("%c", *(tbE+tmp));
}
return tbE;
}
// ------------------------------------------------------
// main
// ------------------------------------------------------
int main(void)
{
char *s; // input from user
char *encryptedString; // encrypted input/output
int loi = 0; // length of input
srand((unsigned)time(NULL)); // initialize random value for encryption
int caesar = (rand()%25) + 1; // random number for caesar encryption
printf("input string : ");
s = inputString(stdin, 10); // realloc the memory space for the input
makeLowerCase(s); // convert to lower case
printf("lower case: %s\n",s);
loi = lengthOfInput(s); // length of the input
printf("lenght of input: %d\n",loi);
printf("caesar number: %d\n",caesar);
encryptedString = encrypt(s, caesar); // encryption
printf("\nencrypted : %s",encryptedString); // output
free(s);
free(encryptedString); // free the memory
return 0;
}
You are using an uninitialized variable.
// encrypts the input caesar
char *encrypt(char *toBeEncrypted, int caesarNum)
{
int tmp = 0; // going through the input
char *tbE;
for(;*toBeEncrypted != '\0'; toBeEncrypted++, tmp++)
{
*(tbE+tmp) = *toBeEncrypted + caesarNum;
// ^
// ^ here tbE is used, but it has never been initialized
//
printf("%c", *(tbE+tmp));
}
return tbE;
}
There may be more issues.
Side note
In encrypt the loop should be written with array indexes rather than with pointer arithmetic for the sake of readability:
for(i = 0; toBeEncrypted[i] != '\0'; i++)
{
tbE[i] = toBeEncrypted[i] + caesarNum;
printf("%c", tbE[i]);
}

segmentation fault (core dumped) error in C program

I tried to compile and run the following program to reverse a string using the gcc compiler for linux but it shows the error : segmentation fault (core dumped).I even tried to debug using gdb but it didn't help. The program given below firstly inputs t which is the number of test cases.I tested the program with 3 test cases but after taking the 2nd input from user, the compiler shows error.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* strrev(char*);
int main(int argc, char *argv[])
{
int t,i=0,temp=0;
char *str[10],*rev[10];
scanf("%d",&t); //input the number of test cases
while(i<t)
{
scanf("%s",str[i]);
i++;
}
while(temp<t) //reverse the string and display it
{
rev[temp]=strrev(str[temp]);
printf("%s \n",rev[temp]);
temp++;
}
return 0;
getchar();
}
Function to reverse the string:
char *strrev(char *str)
{
int i = strlen(str)-1,j=0;
char ch;
while(i>j)
{
ch = str[i];
str[i]= str[j];
str[j] = ch;
i--;
j++;
}
return str;
}
You are getting segmentation fault because you haven't allocated space for elements of str.
You need to allocate memory first in main function.
scanf("%d",&t); //input the number of test cases
if(t <= 10)
for(size_t i = 0; i < t; i++)
str[i] = malloc(50); // Assuming string is no more than 50characters.
else
exit(0);
Beside this there are many flaws in your code. Here is the code after fixing them
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void strrev(char*); // Change return type to void
int main(void)
{
int t,i=0,temp=0, ch;
char *str[10];
scanf("%d",&t); //input the number of test cases
while((ch = getchar()) != EOF && ch != '\n'); // To consume newline character after scanf
// Allocate memory for str elements
if(t <= 10)
for(size_t i = 0; i < t; i++)
str[i] = malloc(50); // Assuming string is no more than 50characters.
else
exit(0);
i = 0;
while(i < t)
{
fgets(str[i],50,stdin); // Use fgets instead of scanf to read string
i++;
}
while(temp<t) //reverse the string and display it
{
// Since you are reversing string by flipping the characters the same
// string just pass pointer to it. str[temp] will be updated in function.
strrev(str[temp]);
printf("Reverse is %s \n", str[temp]);
temp++;
}
return 0;
}
void strrev(char *str)
{
size_t i = strlen(str)-1,j=0;
char ch;
while(i>j)
{
ch = str[i];
str[i]= str[j];
str[j] = ch;
i--;
j++;
}
//printf("Reverse is %s \n", str);
}
you have missed to allocate memory before reading char* value, so you can do this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* strrev(char*);
int main(int argc, char *argv[])
{
int t,i=0,temp=0;
char *str[10],*rev[10];
scanf("%d",&t); //input the number of test cases
while(i<t)
{
str[i] = (char*)malloc(100); // just allocate memory
scanf("%s", str[i]);
i++;
}
while(temp<t) //reverse the string and display it
{
rev[temp]=strrev(str[temp]);
printf("%s \n",rev[temp]);
temp++;
}
return 0;
getchar();
}
char *str[10],*rev[10];
You did not assign storage to hold string values yet for those pointers.
char * str; /* this is a string pointer */
char * str = malloc(15); /* this creates storage for a string */
char str[10]; /* this creates a static char array, also is a string */
I also had the same issue. I just fixed it by correcting the indices of the matrix.

Storing the buffer of fgets in Array

I'm new to C (coming from Java) and naturally that poses some difficulties. I would like to write just a short program that reads in char-Arrays from stdin and stores the individual strings in an array. After reading in the strings I just want to have them printed out, but that's when it gets really confusing for me.
Here's my code:
#include <stdlib.h>
#include <stdio.h>
int main(){
char **stringarray[2];
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
char *tmp = buffer;
stringarray[i] = &tmp;
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", &stringarray[i]);
}
return 0;
}
The first part does in fact compiles (i.e. the part before the print out). I understand that my stringArray has to be an array of char pointers, because that's what a char array basically is in c. It's a pointer to the first character. At first I just wrote
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = buffer;
i++;
}
which also compiled, but of course then I have one pointer that points to buffer, which will only save the last string that has been read.
What do I have to do that I can store a simple array of strings?
I suggest you change your code as following.
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* to use strdup function */
int main(){
char *stringarray[2]; /* I don't understand why you use pointer to pointer than pointer, char **stringarray[2]; */
char buffer[6]; /* I suggest 6 than 5, because string has terminate byte in C */
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = strndup(buffer, 5);
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", stringarray[i]); /* changed stringarray */
}
return 0;
}
char **stringarray[2]; is like char ***stringarray because an array is like a pointer to the first value of the array.
printf wants a char* and &stringarray[i] is a char**
if a string is an array then an array of strings is an array of array.
So the code is :
int main()
{
char stringarray[2][5];//array of (array of char)
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL)
{
strcpy(stringarray[i],buffer); //copies the buffer into the string array
i++;
}
for(i = 0; i < 2; i++)
{
printf("%s\n", stringarray[i]);
}
return 0;
}
If you didn't want to use buffer you could just writte :
while( i < 2 && fgets(stringarray[i], 5, stdin) != NULL)
{
i++;
}
Note that you get 5 characters, the last one will be the NUL terminator \0. And because you have to press enter to validate, the one before \0 will be Line Feed\n. And you will only have 3 characters you really wanted.
You can do it using dynamic allocation technique as below .
#include<stdio.h>
#include<malloc.h>
#include <stdlib.h>
int main()
{
int num;
int len=0;
int i;
printf("Enter the number of elements to be entered ");
scanf("%d",&num);
//Allocate memory for the array of strings
char **var=(char **)malloc(num * sizeof(char *));
for(i=0;i<num;i++)
{
printf("Enter the string : ");
//get strings using getline
getline(&var[i],&len,stdin);
}
for(i=0;i<num;i++)
{
printf("String %d : %s \n",i,var[i]);
}
free(var);
}

Resources