Displaying the contents of a dynamic array backwards - c

So the program is supposed to do the following:
Ask the user to enter strings (max length of the string being 250), and once the user enters nothing (so basically hitting 'enter'), the program stops taking input and proceeds to display every string the user has input backwards.
Here's my code - everything works except I can't enter the while loop at the bottom.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char userInput[250];
char *newSpace;
char *array;
int stringLength;
int inputElems = 0;
//Reset startingPtr back to where 'array' begins
char *startingPtr = array - inputElems;
// Sets endPtr to the last input element in the array
char *endPtr = startingPtr + inputElems;
do
{
puts("Please enter a string!");
// Gets input from user
fgets(userInput, 250, stdin);
// Finds out the number of characters the user entered
// + 1 to make room for the null character
stringLength = strlen(userInput) + 1;
// Allocate memory with the needed space
newSpace = malloc(stringLength);
// If malloc didn't allocate memory, display error
if (NULL == newSpace)
{
puts("Error!");
}
// Copy user input into array
strcpy(newSpace, userInput);
// Save input into array
array = newSpace;
// For testing purposes only, this line will be deleted once I can access the array
//puts("Here's what you wrote");
//printf("%s", array);
// Increase array
array++;
// Increase number of times user has input something
inputElems++;
} while(stringLength != 2);
//puts("Testing outside");
while (endPtr > startingPtr)
{
//puts("Testing inside");
--endPtr;
printf("%s", *endPtr);
}
free(newSpace);
}

Your while loop body is never executed because you never modify endPtr and startingPtr throughout the program's lifetime, they both point to the same location. Thus, endPtr > startingPtr will never be true.
Also, array++ does not work the way you expect: array points to the first character of what the user wrote, and array++ just moves it forward to the next character. I think you want an array of char *. Thus, change char *array; to char *array[250]; (assuming that the user can enter at most 250 sentences).
And of course, since you can't increment an array, because an array is not a modifiable l-value, you must also keep a count for the last index written. But I see that you already have inputElems, that should be enough. Here's the modified code:
int main()
{
char userInput[250];
char *newSpace;
char *array[250];
int stringLength;
int i;
int inputElems = 0;
do
{
puts("Please enter a string!");
// Gets input from user
fgets(userInput, 250, stdin);
// Finds out the number of characters the user entered
// + 1 to make room for the null character
stringLength = strlen(userInput) + 1;
// Allocate memory with the needed space
newSpace = malloc(stringLength);
// If malloc didn't allocate memory, display error
if (NULL == newSpace)
{
puts("Error!");
}
// Copy user input into array
strcpy(newSpace, userInput);
// Save input into array
array[inputElems] = newSpace;
// For testing purposes only, this line will be deleted once I can access the array
//puts("Here's what you wrote");
//printf("%s", array);
// Increase number of times user has input something
inputElems++;
} while(stringLength != 2);
//puts("Testing outside");
for (i = inputElems-1; i >= 0; i++)
{
//puts("Testing inside");
printf("%s", array[i]);
free(array[i]);
}
return 0;
}
Note the updated loop in the end of the code. It goes through the array from end to beginning. Note that I changed the place where you call free(). Since we're allocating memory inside a loop, for each position in array, we must also free() every position, thus this must also be made inside a loop.

Ok. you need an array of pointers like: char *arr[10];
You can store here 10 strings from arr[0] to arr[9]. (Well not directly 10 strings, but the pointers to them)
arr[0] = (char*)malloc(sizeof(char * length_of_string));
strncpy(arr[0], your_string, length_of_string);
When just print arr[9] to arr[0].
mfg

Related

Assigning value to pointer correctly in C using strcpy()

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
//...

How to read strings from stdin into a two-dimensional array in c programming using scanf() and while loop?

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;
}

How to handle buffer error while validating user input

I need to read in user input as an integer to pass it to my other function. If I use my validation (code below), it crashes after 4 bad inputs. I'm not completely sure if this is even a buffer error or not. But I also didn't find a proper way to validate my input and handle the errors. I didn't use scanf(%d) on purpose because I wanted to dodge the warning CLion is giving me when using it. I hope someone here can explain to me why my code is crashing after 4 bad inputs and how to fix it, or show me an alternative way.
char *userInput = malloc(100);
long amountOfPlayers;
//Todo: More Validation needed, bufferoverflow
for (int i = 0; i < sizeof(userInput) / sizeof(*userInput); i++) {
char *end;
printf("Please enter the amount of players: ");
scanf("%s", userInput);
amountOfPlayers = strtol(userInput, &end, 10);
if (end == userInput) {
printf("wasn't a number\n");
}
else if (end[0] != '\0') {
printf("trailing characters after number %ld: %s\n", amountOfPlayers, end);
}
else
return init_playerList(amountOfPlayers);
}
userInput is a pointer, not an array, so sizeof(userInput) returns the size of a pointer, typically 4 bytes. sizeof(*userInput) is sizeof(char), which is 1. So sizeof(userInput) / sizeof(*userInput) is 4, which means your for loop only executes 4 times. See How to find the 'sizeof' (a pointer pointing to an array)?
There's no need for a for loop, just use while (true). You're not doing anything that iterates over the elements of userInput, it's just the buffer.
There's also no reason to allocate it with malloc(), you can simply declare:
char userInput[100];
You have a memory leak because you never free(userInput) before returning from the function. But if you declare it as an array this is not necessary.
TO prevent buffer overflow you should use:
scanf("%100s", userInput);
sizeof(userInput) / sizeof(*userInput) won't return the number of elements, because userInput is a pointer, not an array. This only works for pure arrays. In case of pointer is always return the same value: size of a pointer divided by the size of the object.
int size = 100;
char *userInput = malloc(size);
if(userInput == NULL)
{
// error handling
}
for (int i = 0; i < n; i++) {
....
}
would be correct.

How to input strings into an array in C?

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.

While Loop clearing my array? (C)

I've been hard at this problem for a bit and am wondering if anybody can find what Im doing wrong. Im reading user input from stdin, breaking up the string they input via strtok(), and storing it into an array of char *'s. The array of char *'s is defined outside of the while loop.
So: a user types in input via stdin, and an array is filled with strings with each word from the command.
The thing is, if the user simply hits enter I want the array to MAINTAIN it's value! I want the same values to stay in the array...so I can re-execute the same command. It appears that the while loop is clearing my array of char*'s instead. Here's code:
char *commands[3];
char *result = NULL;
char delims[] = " "; //a space AND a tab!
while (1) {
printf(PROMPT);
//Gathers user input!
char *input;
char stuff[230];
input = fgets(stuff, 230, stdin);
printf("input has length %i\n", strlen(input));
int helper = strlen(input);
int i = 0;
result = strtok(input, delims);
printf("helper has length %i\n", helper);
printf("commands[0] CHECK 1:%s", commands[0]);
if (helper >1)
{
while( result != NULL)
{
printf("while gets hit!\n");
if (i < 4)
{
commands[i] = result;
result = strtok(NULL, delims );
i++;
}
}
}
printf("commands[0] is CHECK 2:%s", commands[0]);
if (strncmp(commands[0], "step", 4) == 0)
{
lc3_step_one(p);
}
printf("commands[0] is CHECK 3:%s", commands[0]);
}
The printf's CHECK 1, CHECK 2,and CHECK 3 all print nothing if the user hits enter. In the case they last typed "step" I want "step" to stay in the array and thusly be executed again!
You are filling the commands array with pointers to the stuff array. That array is being overwritten by the fgets each time (probably replacing the first character with null). You would need to copy the data out to preserve it.

Resources