I tried to get the inputs(strings) from user and store them in an array.But after I ran this code, the program instantly crashed.
#include <stdio.h>
int main() {
int i;
char *word[3];
for(i=0;i<3;i++)
{
printf(" Enter a word: ");
scanf("%s", &word[i]);
}
printf("%s ", word[0]);
return 0;
}
In this line:
scanf("%s", &word[i]);
You need to make sure word[i] is pointing somewhere, and has enough space to occupy the string entered. Since word[i] is a char * pointer, you need to at some time allocate memory for this. Otherwise, it is just a dangling pointer not pointing anywhere.
If you want to stick with scanf(), then you can allocate some space beforehand with malloc.
malloc() allocates requested memory on the heap, then returns a void* pointer at the end.
You can apply malloc() in your code like this:
size_t malloc_size = 100;
for (i = 0; i < 3; i++) {
word[i] = malloc(malloc_size * sizeof(char)); /* allocates 100 bytes */
printf("Enter word: ");
scanf("%99s", word[i]); /* Use %99s to avoid overflow */
/* No need to include & address, since word[i] is already a char* pointer */
}
Note: Must check return value of malloc(), because it can return NULL when unsuccessful.
Additionally, whenever you allocate memory with the use of malloc(), you must use free to deallocate requested memory at the end:
free(word[i]);
word[i] = NULL; /* safe to make sure pointer is no longer pointing anywhere */
Another approach without scanf
A more proper way to read strings should be with fgets.
char *fgets(char *str, int n, FILE *stream) reads a line from an input stream, and copies the bytes over to char *str, which must be given a size of n bytes as a threshold of space it can occupy.
Things to note about fgets:
Appends \n character at the end of buffer. Can be removed easily.
On error, returns NULL. If no characters are read, still returns NULL at the end.
Buffer must be statically declared with a given size n.
Reads specified stream. Either from stdin or FILE *.
Here is an example of how it can be used to read a line of input from stdin:
char buffer[100]; /* statically declared buffer */
printf("Enter a string: ");
fgets(buffer, 100, stdin); /* read line of input into buffer. Needs error checking */
Example code with comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMSTR 3
#define BUFFSIZE 100
int main(void) {
char *words[NUMSTR];
char buffer[BUFFSIZE];
size_t i, count = 0, slen; /* can replace size_t with int if you prefer */
/* loops only for three input strings */
for (i = 0; i < NUMSTR; i++) {
/* read input of one string, with error checking */
printf("Enter a word: ");
if (fgets(buffer, BUFFSIZE, stdin) == NULL) {
fprintf(stderr, "Error reading string into buffer.\n");
exit(EXIT_FAILURE);
}
/* removing newline from buffer, along with checking for overflow from buffer */
slen = strlen(buffer);
if (slen > 0) {
if (buffer[slen-1] == '\n') {
buffer[slen-1] = '\0';
} else {
printf("Exceeded buffer length of %d.\n", BUFFSIZE);
exit(EXIT_FAILURE);
}
}
/* checking if nothing was entered */
if (!*buffer) {
printf("No string entered.\n");
exit(EXIT_FAILURE);
}
/* allocate space for `words[i]` and null terminator */
words[count] = malloc(strlen(buffer)+1);
/* checking return of malloc, very good to do this */
if (!words[count]) {
printf("Cannot allocate memory for string.\n");
exit(EXIT_FAILURE);
}
/* if everything is fine, copy over into your array of pointers */
strcpy(words[count], buffer);
/* increment count, ready for next space in array */
count++;
}
/* reading input is finished, now time to print and free the strings */
printf("\nYour strings:\n");
for (i = 0; i < count; i++) {
printf("words[%zu] = %s\n", i, words[i]);
free(words[i]);
words[i] = NULL;
}
return 0;
}
Example input:
Enter a word: Hello
Enter a word: World
Enter a word: Woohoo
Output:
Your strings:
words[0] = Hello
words[1] = World
words[2] = Woohoo
There seems to be a bit of confusion in this area. Your primary problem is you are attempting to write each word to the address of each of pointers you declare with char *word[3];. (not to mention you have no storage allocated at the location pointed to by each pointer -- but you never get there as you attempt to write to the address of each pointer with &word[i] rather than to the pointer itself)
While you can use scanf you will quickly run into one of the many pitfalls with taking user input with scanf that plague all new C programmers (e.g. failing to handle the '\n' left in the input buffer, failing to handle whitespace in strings, failing to limit the number of characters read/written, failing to validate the read or handle EOF, etc...)
A better approach is to simply use fgets and then trim the '\n' that fgets read and includes in the buffer to which it stores the string. A simple example would be:
#include <stdio.h>
#include <string.h>
#define NWDS 3 /* declare a constant for the maximum number of words */
int main (void) {
int i, n = 0;
char word[NWDS][50] = { "" }; /* provide storage or allocate */
for (i = 0; i < NWDS; i++) { /* for a max of NWDS */
printf ("Enter word : "); /* prompt */
if (!fgets (word[i], sizeof word[i], stdin)) /* read/validate */
break; /* protect against EOF */
size_t len = strlen (word[i]); /* get length */
if (word[i][len-1] == '\n') /* check for trailing '\n' */
word[i][--len] = 0; /* overwrite with nulbyte */
}
n = i; /* store number of words read */
putchar ('\n'); /* make it pretty */
for (i = 0; i < n; i++) /* output each word read */
printf (" word[%d] : %s\n", i, word[i]);
#if (defined _WIN32 || defined _WIN64)
getchar(); /* keep terminal open until keypress if on windows */
#endif
return 0;
}
Go ahead and cancel input at any time by generating an EOF during input (ctrl + d on Linux or ctrl + z on windoze), you are covered.
Example Use/Output
$ ./bin/wordsread
Enter word : first word
Enter word : next word
Enter word : last word
word[0] : first word
word[1] : next word
word[2] : last word
Looks things over, consider the other answers, and let me know if you have further questions.
char *word[3]; // <-- this is an array of 3 dangling pointers, of type char*
// they still point nowhere, we later need to set them to some allocated location.
...
for(i=0;i<3;i++) {
word[i] = malloc(some_max_size * sizeof(char)); // <-- allocate space for your word
printf(" Enter a word: ");
scanf("%s", word[i]); // <-- not &word[i]; word[i] is already a char* pointer
}
You are declaring word as array of pointer (char *word[3];). You have to allocate memory to store data. Allocate memory with malloc or similar functions before assigning values.
Yes the code crashes because declaring an array of character
pointers is not enough, you need to set the pointers to point
to memory where the strings can be stored.
E.g.
const int maxLen = 32;
char* word[3] = {NULL,NULL,NULL};
word[i] = malloc(maxLen);
then read the string from keyboard, to ensure that the string is not too
long use fgets and maxLen:
printf("Enter a word:");
fgets(word[i],maxLen,stdin);
#include <stdio.h>
int main(){
int n;
int i=0;
scanf("%d",&n);
char arr[n];
while(n>i){
scanf("%s",&arr[i]);
i+=1;
}
while(n-i<n){
printf(" %c ",arr[n-i]);
i-=1;
}
}
The code char *word[3] made a 3-element array of pointers!
See, you have basically created a character array of pointers, so you cannot put a "string" into each one of them, because the type of a pointer variable is long hexadecimal.
Related
char* str = NULL;
size_t capacity = 0;
getline(&str, &capacity, stdin);
The above code is an example of using getline to dynamically allocate memory while reading a string input. But, what if I'm trying to read the input into a 2D array?
Example:
Linenumberone (enter)
Linenumbertwo (enter)
(enter) <<< enter on an empty line - stop reading user input
I do know about the function strlen, so I was thinking I could technically use that to figure out when to stop reading user input? But I'm a bit confused, is it even possible to read user input using getline into a 2D array in C as described? I've only seen people using it in C++
We can declare an array of pointers, then assign each line to the 2D array in a loop. See the code below:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *line[5] = {NULL}; // array of 5 pointers
size_t len = 0;
int i=0;
for(i=0;i<5;i++)
{
getline(&line[i],&len, stdin); // reading strings
}
printf("\nThe strings are \n");
for(int i=0; i<5; i++)
{
printf("%s",line[i]); // prinitng the strings.
}
return 0;
}
The output is (first 5 lines are input) :
krishna
rachita
teja
sindhu
sagarika
The strings are
krishna
rachita
teja
sindhu
sagarika
Each time characters = getline(&str,...) is used, new dynamic memory is allocated at the address str, with a size equal to number of characters read. It suffices to store the buffer address (value of str) into an array at each getline() call. Subsequently, the buffer address (str) in getline() is incremented by the number of characters read in the last getine(). See code and example below.
#include <stdio.h>
int main () {
char *buffer=NULL;
size_t capacity = 0;
size_t maxlines = 100;
char *lines[maxlines]; // pointers into the malloc buffer for each line
printf ("Input\n\n");
int lines_read;
int characters;
// read getline until empty line or maxlines
for (lines_read = 0; lines_read < maxlines; lines_read++) {
printf ("Enter line %d: ", lines_read + 1);
characters = getline (&buffer, &capacity, stdin);
// stop at empty line
if (characters == 1) break;
// convert end of line "\n" into zero (C null-terminated string convention)
buffer[characters - 1] = 0;
// save starting location into lines
lines[lines_read] = buffer; // save pointer to the start of this line in the buffer
buffer += characters; // set pointer to the start of a new line in the buffer
}
printf ("\nOutput\n\n");
// print lines read excluding empty line
for (int i = 0; i < lines_read; i++)
printf ("Line[%d] = %s\n", i+1, lines[i]);
return (0);
}
Example output:
Input
Enter line 1: This
Enter line 2: is
Enter line 3: an
Enter line 4: example.
Enter line 5:
Output
Line[1] = This
Line[2] = is
Line[3] = an
Line[4] = example.
I need to take only the odd values from a char array and copy them into correctly sized dynamic memory using a pointer.
However when running my program it works correctly with certain input strings and not with others. Is there something that I'm doing wrong? I can't seem to figure out what's going on.
/* A.) Include the necessary headers in our program */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 32
int main() {
/* B.) Declare char array with inital size of 32 */
char input_string[MAX_STRING_LENGTH];
/* C.) Recieve user input.
Can save the first 31 characters in the array with 32nd reserved for '\0' */
printf("Enter a string of characters: ");
/* D.) Using the technique we discussed to limit the string to 31 charaters */
scanf("%31s", input_string);
printf("\n");
/* Will be used to determine the exact amount of dynamic memory that will be allocated later */
int odd_value_count = 0;
printf("Odd Characters: ");
for(int i = 0; i < strlen(input_string); i++) {
if(i % 2 != 0) {
printf("%c ", input_string[i]);
odd_value_count++;
}
}
printf("\n");
printf("Odd value count: %d\n", odd_value_count);
/* E.) Delecaring the pointer that will hold some part of the input_string
Pointer will be a char type */
char *string_pointer;
/* G.) Allocating the space before the copy using our odd value count */
/* H.) The exact amount of space needed is the sizeof(char) * the odd value count + 1 */
string_pointer = (char *)malloc(sizeof(char) * (odd_value_count + 1));
if (string_pointer == NULL) {
printf("Error! Did not allocte memory on heap.");
exit(0);
}
/* F.) Copying all charcters that are on the odd index of the input_string[] array
to the memory space pointed by the pointer we delcared */
printf("COPIED: ");
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
printf("%c ", input_string[i]);
}
}
/* Printing out the string uses the pointer, however we must subtract odd_value_count to
position the pointer back at the original start address */
printf("\n%s\n", string_pointer - odd_value_count);
return 0;
}
This input string: 01030507
works fine and copies & prints: 1357
The input string: testing
Copies etn but prints etng.
I cant figure out why for some strings it prints out the extra character at the end when I never even copy the value over.
You need to Null Terminate your string, like this *string_pointer = '\0';, just after you are done copying the odd characters in your string pointer - after that loop, null terminate your string.
Read more in How to add null terminator to char pointer, when using strcpy?
In the end of your routine you will need to null terminate the string, otherwise you don't have a string you just have a char array, you can use string_pointer which is already pointing to one past the end of the string you want to save:
//...
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
//as you are copying characters, you can do this:
//*string_pointer++ = input_string[i];
//instead of strcpy
printf("%c ", input_string[i]);
}
}
*string_pointer = '\0'; // <-- here
//...
I'm writing a c code to read strings from stdin with scanf() and while loop (into a two-dimensional char array). My strategy is to use an input array to temporarily store each string and then assign it to a preword array (fixed sized). However, my strategy failed and all strings stored in my arrays are the same (the last string input). How to fix it?
I used a fgets() and it works find. However, I cannot use it to deal with a new line of strings (from stdin). My fgets() reads only the first line and that's why I turn to scanf and while loop.
#include<stdio.h>
#include<stdlib.h>
#define MAX 1000
#define size 50
int main ()
{
int count = 0;
char input[size];
char * preword[MAX];
while (scanf("%s",input)!= EOF){
preword[count] = input;
printf("preword[%d] is %s\n",count,preword[count]);
count++;
}
printf("the count is %d\n",count);
for (int i = 0; i < count; i++){
printf("preword[%d] is %s\n",i,preword[i]);
}
return 0;
}
I expect my input arrays from stdin will be stored in a two-dimensional char array. Below is the output in terminal after compilation. My input is a txt file, in which I have
hello world
I am a hero
It turns out that all strings stored in the two-d array are the last word.
preword[0] is hello
preword[1] is world
preword[2] is I
preword[3] is am
preword[4] is a
preword[5] is hero
the count is 6
preword[0] is hero
preword[1] is hero
preword[2] is hero
preword[3] is hero
preword[4] is hero
preword[5] is hero
Firstly here
char * preword[MAX];
preword is array of character pointer i.e each element is a char pointer & when you are doing like
preword[count] = input;
as #paddy pointed its copies input in every element of preword and it's the same pointer since you haven't allocated memory for preword[count], correct way is to allocate memory for each pointer and then copy.
Also use fgets() instead of scanf() here. For e.g
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 1000
#define size 50
int main (void)
{
int count = 0;
char input[size] = {0};
char * preword[MAX] = {0};
size_t retStrCspn = 0;
while (fgets(input, size, stdin) != NULL){
/* remove trailing new line if its stored at end of buffer by fgets() */
input[retStrCspn = strcspn(input, "\n")] = 0; /* remove the trailing & use the return value for allocating memory purpose \n */
preword[count] = malloc(retStrCspn + 1); /* Allocate memory for each pointer elements */
if(preword[count] != NULL) {
memcpy (preword[count], input, retStrCspn + 1); /* copy input buffer into each different memory location */
printf("preword[%d] is %s\n",count,preword[count]);
count++;
}
else {
/* #TODO malloc erro handling */
}
}
printf("the count is %d\n",count);
for (int i = 0; i < count && preword[i] != NULL; i++){
printf("preword[%d] is %s\n",i,preword[i]);
free(preword[count]); /* free dynamically allocated memory here*/
}
return 0;
}
Hey guys i've been having some problems with this problem. I have tried it many ways from looping with stdin and saving each letter to scanf(" %s") into an array then declaring the array as a pointer then returning the pointer. I have come close but have mainly had problems when having spaces in my string that I enter. The program needs to call this char* that gets the pointer to the string, twice and then output both strings line after line. Any help greatly appreciated.
char* get_input()
{
char c = 'a';
int counter = 1;
while(c != '\0')
{
c = getc(stdin);
char* d = (char)malloc(sizeof(char)*counter);
*(d+counter) = c;
counter++;
return d;
}
return d;
}
So i was thinking something like this was the best way to do it but i dont know how to return the pointer out of the while loop and then again into the char*. What i really need is some guidance on the best way to store some input straight into an allocated array that will not waste any memory(it will know how long the string you entered is and allocate enough memory) i have also tried with scanf("%s") but i dont know how to stoe the data from scanf into a dynamic memory chunk.
And sorry dont have my actual code atm cause at work and my program is at home. Any ideas pls
your earlier code:
char* get_input()
{
char c = 'a';
int counter = 1;
while(c != '\0')
{
c = getc(stdin);
char* d = (char)malloc(sizeof(char)*counter);
*(d+counter) = c;
counter++;
return d;
}
return d;
}
Oh, no, no, no! You create a separate pointer address pointing to a counter size block of memory with each call to malloc, assign it to d, and then attempt to assign c to *(d+counter) which writes beyond the end of the current block, and which has absolutely no way of knowing what d was during the previous iteration -- sigh...
First, there are as many ways to do dynamic input as there are colors in a rainbow... It can be as simple and witless as using scanf with the %m conversion specifier (older versions and windows use %a). It comes with all the pitfalls that scanf brings with it. However, it can work:
char *get_input_scanf()
{
char *ln = NULL;
scanf ("%m[^\n]%*c", &ln);
return ln;
}
But there are absoutely no limitations on data entry and very little control. (note: unless you pass additional information to any input function or use global #defines or variables, any input method will suffer from this limitation. Consider passing a max length to the input function, or make sure you validate the return)
You can also read character-by-character with getchar() or getc(fp), or you can use line-input methods like fgets or getline. With any of these methods (except getline), you will need to allocate a temporary line buffer to hold the input, and then in order to limit allocation to the amount required, allocate your final buffer based on the strlen + 1 of your input (or use just use strdup). As with all dynamic approaches, you are responsible for tracking it, preserving the start address to the memory block, and freeing the memory when it is no longer needed. Beyond that, the sky is the limit on what you do with the function.
An example of a dynamic input routine with getline could look like the following:
char *get_input()
{
char *ln = NULL; /* line buffer, NULL - getline allocates */
size_t n = 0; /* initial buff size, 0 - getline decides */
ssize_t nchr = 0; /* getline return - actual no. of chars read*/
if ((nchr = getline (&ln, &n, stdin)) != -1)
{
/* strip newline or carriage rtn */
while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
ln[--nchr] = 0;
/* if (!nchr) { // do not accept blank lines
free (ln);
return NULL;
} */
char *input = strdup (ln); /* duplicate ln in input */
free (ln); /* free getline allocated mem */
return input;
}
return NULL;
}
Note: as discussed above, getline imposes no limitation on how long the input string can be, so it is up to you to validate.
There is no limit on the number of different ways you can do dynamic input. (there are probably at least 1000 examples here on SO already) However, it all boils down to either character or line input, so make your choice as to what method you want to use and then write your code. Here is a small working example with the two different functions above. Look over the post and let me know if you have questions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_input();
char *get_input_scanf();
int main (void) {
char *line = NULL;
printf ("\nEnter input below, [ctrl+d] to quit\n");
for (;;)
{
printf ("\n input: ");
line = get_input();
if (line)
printf (" value: '%s'\n", line);
else {
printf ("\n value: [ctrl+d] received\n");
break;
}
free (line);
line = NULL;
}
if (line) free (line);
printf ("\n");
line = NULL;
printf ("\nEnter input below to read with get_input_scanf\n\n input: ");
line = get_input_scanf();
if (line) {
printf (" value: '%s'\n", line);
free (line);
}
return 0;
}
char *get_input()
{
char *ln = NULL; /* line buffer, NULL - getline allocates */
size_t n = 0; /* initial , 0 - getline decides*/
ssize_t nchr = 0;
if ((nchr = getline (&ln, &n, stdin)) != -1)
{
/* strip newline or carriage rtn */
while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
ln[--nchr] = 0;
/* if (!nchr) { // do not accept blank lines
free (ln);
return NULL;
} */
char *input = strdup (ln); /* duplicate ln in input */
free (ln); /* free getline allocated mem */
return input;
}
return NULL;
}
char *get_input_scanf()
{
char *ln = NULL;
scanf ("%m[^\n]%*c", &ln);
return ln;
}
Example Use/Output
$ ./bin/getline_getinput
Enter input below, [ctrl+d] to quit
input: some string of input.
value: 'some string of input.'
input: another string that can be any length ........ ........
value: 'another string that can be any length ........ ........'
input:
value: ''
input: a
value: 'a'
input:
value: [ctrl+d] received
Enter input below to read with get_input_scanf
input: some input to show scanf will allocate dynamically as well!
value: 'some input to show scanf will allocate dynamically as well!'
This is a problem I don't understand - I am using fgets() in main and it works. I use it (I think) in exactly the same way in a function and I get an error [Segmentation fault core dumped -- exit code 139).
This code is based on a sample program in book Ivor Horton's "Beginning C" (it's a old tile but I'm just wanting to learn the basics from it).
My program is as follows. I am working on *nix using Geany (basically, compiling with GCC). You can see that fgets works in main (output is the string you enter). But it doesn't work in the function str_in(). It gets as far as the second printf() statement to enter a string, no further. Note that in the book, Horton uses gets(). I am trying to implement a safer string input function here, but no joy.
By the way the program is supposed to sort strings stored in an array of string pointers.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define MAX_NUM_STRINGS 50
int str_in(char **); /*Pointer to a string pointer*/
void str_sort(char *[], int n); /*Array of pointers to strings, number of strings in array*/
void str_out (char *[], int n); /*Array of pointers to strings, number of strings in array*/
int main(){
char *pS[MAX_NUM_STRINGS] = { NULL }; /*Array of pointers to strings stored in str_space*/
int numStrings = 0; /*Count of strings*/
char buffer[BUFSIZ];
printf("Enter a string\n");
fgets(buffer, BUFSIZ, stdin);
printf("%s", buffer);
printf("fgets works here\n\n");
/* get string input from user - a pointer to each string is saved in pS */
while ( str_in(&pS[numStrings]) && numStrings < MAX_NUM_STRINGS)
numStrings++;
if ( numStrings > 0 ){
str_sort(pS, numStrings);
str_out(pS, numStrings);
}
return 0;
}
int str_in(char** pString){
char buffer[BUFSIZ];
char *p;
printf ("Enter string:\n");
fgets(buffer, 60, stdin);
printf("fgets doesn't work here!!\n");
if( buffer != NULL ){
printf("here");
if ((p = strchr(buffer, '\n')) != NULL)
*p = '\0'; /*replace newline with null character*/
else
return FALSE;
if ( strlen(buffer) > 0 ){
strcpy(*pString, buffer);
return TRUE;
}
else
return FALSE; /*blank line - end of input*/
}
else
return FALSE;
}
void str_sort(char* pStrings[], int n){
/*sort strings by manipulating array of string pointers*/
char *temp;
int sorted = FALSE;
int i = 0;
while (!sorted){
sorted = TRUE;
for(i = 0; i < n - 1; i++){
temp = pStrings[i];
if ( strcmp(temp, pStrings[i+1]) > 1 ){
pStrings[i] = pStrings[i+1];
pStrings[i+1] = temp;
sorted = FALSE;
break;
}
}
}
}
void str_out(char* pStrings[], int n){
/*print strings to standard output. Free memory as each string is printed */
int i = 0;
printf("Sorted strings:\n");
for(i = 0; i < n; i++){
printf("%s", pStrings[i]);
free(pStrings[i]);
}
}
The segmentation fault is not caused by fgets(), but by strcpy():
strcpy(*pString, buffer);
You try to write to *pString, but you never allocate memory for it. pS in main() is just an array of null pointers.
Another thing is with the test with if( buffer != NULL ), that would never be true since buffer is an array, not a pointer.
You must check for the return value of fgets to see if you have successfully received something, if not then you should never use your buffer as a string as you are not NUL terminating the buffer.
/* Checking for buffer != NULL is of no use */
/* as buffer will always be not NULL since */
/* since you have allocated it as char buffer[BUFSIZ] */
if (fgets(buffer, BUFSIZ, stdin) == NULL) {
/* buffer may not be a valid string */
}
So what you can do it to initialize the buffer to a NUL string, as soon as you enter the function (after your declarations are done
buffer[0] = 0; /* initialize to NUL string */
now you can use buffer as a string anywhere.
Also note than if BUFSIZ is too big greater than a couple of KB, then your might get seg fault due to stack overflow. If they are too big you could make buffer as "static char" instead of "char".