malloc with user input - c

I'm trying to make a program where a user inputs a string then if they want to enter a letter they want to replace and what with. I want to use malloc to set the array but how would I do it with scanf?
Please can someone help.
Thanks!
This is what the program looks before going to the replace method:
char *s,x,y;
printf("Please enter String \n");
scanf("%s ", malloc(s));
printf("Please enter the character you want to replace\n");
scanf("%c ", &x);
printf("Please enter replacment \n");
scanf("%c ", &y);
prinf("%s",s);

You can't know the size of the user input beforehand, so you need to dynamically allocate more memory if the user input hasn't ended yet.
An example would be:
//don't forget to free() the result when done!
char *read_with_alloc(FILE *f) {
size_t bufsize = 8;
char *buf = (char *) malloc(bufsize);
size_t pos = 0;
while (1) {
int c = fgetc(f);
//read until EOF, 0 or newline is read
if (c < 0 or c == '\0' or c == '\n') {
buf[pos] = '\0';
return buf;
}
buf[pos++] = (char) c;
//enlarge buf to hold whole string
if (pos == bufsize) {
bufsize *= 2;
buf = (char *) realloc((void *) buf, bufsize);
}
}
}
A pragmatic alternative solution would be to limit the buf size (for example, to 256 characters), and to make sure that only that number of bytes is read:
char buf[256]; //alternative: char *buf = malloc(256), make sure you understand the precise difference between these two!
if (scanf("%255s", buf) != 1) {
//something went wrong! your error handling here.
}

scanf("%s ", malloc(s));
What does this mean? s uninitialized is pointer, it can have any value, say 0x54654, it is Undefined Behavior.
Your code should be,
int size_of_intput = 100; //decide size of string
s = malloc(size_of_intput);
scanf("%s ", s);

Related

How to use scanf() to capture only Strings

Hi i am new to C and i am trying to use the Character array type below to captures input from users. How do i prevent or escape numerical characters. I just want only strings to be captured.
char str_input[105];
In have tried
scanf("%[^\n]s",str_input);
scanf("%[^\n]",str_input);
scanf("%[^0-9]",str_input);
scanf("%[A-Zaz-z]",str_input);
str_input = fgetc(stdin);
None of the above worked for me.
Input
2
hacker
Expected Output
Hce akr
int main() {
char *str_input;
size_t bufsize = 108;
size_t characters;
str_input = (char *)malloc(bufsize * sizeof(char));
if (str_input == NULL)
{
perror("Unable to allocate buffer");
exit(1);
}
characters = getline(&str_input,&bufsize,stdin);
printf("%zu characters were read.\n",characters);
int i;
int len = 0;
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2==0? printf("%c",str_input[i]): 'b';
}
printf(" ");
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2!=0? printf("%c",str_input[i]): 'b';
}
return 0;
}
Error
solution.c: In function ‘main’:
solution.c:21:5: warning: implicit declaration of function ‘getline’ [-Wimplicit-function-declaration]
characters = getline(&str_input,&bufsize,stdin);
Since your buffer has limited size, then using fgets(3) is fine. fgets() returns NULL on failure to read a line, and appends a newline character at the end of the buffer.
In terms of preventing numerical characters from being in your buffer, you can simply create another buffer, and only add non-numerical characters to it. You could just delete the numerical characters from your original buffer, but this can be a tedious procedure if you are still grasping the basics of C. Another method would be just to read single character input with getchar(3), which would allow you assess each character and simply ignore numbers. THis method is by far the easiest to implement.
Since you asked for an example of using fgets(), here is some example code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define INPUTSIZE 108
int main(void) {
char str_input[INPUTSIZE], characters[INPUTSIZE];
size_t slen, char_count = 0;
printf("Enter input:\n");
if (fgets(str_input, INPUTSIZE, stdin) != NULL) {
/* removing newline from fgets() */
slen = strlen(str_input);
if (slen > 0 && str_input[slen-1] == '\n') {
str_input[slen-1] = '\0';
} else {
fprintf(stderr, "Number of characters entered exceeds buffer size\n");
exit(EXIT_FAILURE);
}
/* checking if string is valid */
if (*str_input == '\0') {
fprintf(stderr, "No input found\n");
exit(EXIT_FAILURE);
}
printf("Buffer: %s\n", str_input);
/* only adding non-numbers */
for (size_t i = 0; str_input[i] != '\0'; i++) {
if (!isdigit(str_input[i])) {
characters[char_count++] = str_input[i];
}
}
/* terminating buffer */
characters[char_count] = '\0';
printf("New buffer without numbers: %s\n", characters);
}
return 0;
}
Example input:
Enter input:
2ttt4y24t4t3t2g
Output:
Buffer: 2ttt4y24t4t3t2g
New buffer without numbers: tttytttg
Update:
You could just use this even simpler approach of ignoring non-number characters:
char str_input[INPUTSIZE];
int ch;
size_t char_count = 0;
while ((ch = getchar()) != EOF && ch != '\n') {
if (!isdigit(ch)) {
if (char_count < sizeof(str_input)) {
str_input[char_count++] = ch;
}
}
}
str_input[char_count] = '\0';
If you're using Linux, I would use the getline() function to get a whole line of text, then verify it. If it is not valid input, I would in a loop ask the user to enter a line of text again and again until you the input is acceptable.
If not using Linux, well, your best bet is probably to reimplement getline(). You can also use fgets() if you find a limited-size buffer acceptable. I don't find limited-size buffers acceptable, so that's why I prefer getline().
getline() is used according to the way explained in its man page: http://man7.org/linux/man-pages/man3/getdelim.3.html
Basically, your loop should be something similar to:
char *buf = NULL;
size_t bufsiz = 0;
while (1)
{
if (getline(&buf, &bufsiz, stdin) < 0)
{
handle_error();
}
if (is_valid(buf))
{
break;
}
printf("Error, please re-enter input\n");
}
use_buffer(buf);
free(buf);
Well that's not possible. Numbers are string too. But you can set loop to look for numbers and print error. like this :
char *str = "ab234cid20kd", *p = str;
while (*p) { // While there are more characters to process...
if (isdigit(*p)) { // Upon finding a digit, ...
printf("Numbers are forbidden");
return 0;
} else {
p++;
}
}

Heap Corruption Detected C

I've been dangling with C and a bit of cryptography, anyways I try to dynamically allocate a string to input a plain text and a key which i use to get a cypher text. Program works until I decide to free the allocated memory. then produces an error stating: HEAP CORRUPTION DETECTED: after Normal block (#73) at this and this address; checked all the other posts, nothing, I'm confused, pls help. Here's the code :
int main(int argc, char *argv[])
{
int plainSize = 0;
int keySize = 0;
InputInteger(keySize,"key size");
InputInteger(plainSize,"plaintext size");
char *plaintext = (char*)malloc((plainSize + 1) * sizeof(char));
char *key = (char*)malloc((keySize + 1) * sizeof(char));
char *cypher = (char*)malloc((plainSize + 1) * sizeof(char));
InputString(plaintext, "plaintext");
InputString(key, "key");
cypher=ViginereEncrypt(plaintext, key);
printf("\n%s encypted with Viginere key %s is %s", plaintext, key, cypher);
printf("\n\n");
free(plaintext);
free(key);
free(cypher);
}
char *ViginereEncrypt(char *plaintext,char *key)
{
int i = 0;
char *cypherText = (char*)malloc((strlen(plaintext) + 1)*sizeof(char));
printf("\n%d\n", strlen(plaintext) + 1);
for (i = 0;i < strlen(plaintext);i++)
*cypherText++ =(*plaintext++ - 'A' + *key++ - 'A' -1) % ('Z' - 'A') + 'A';
cypherText[i] = '\0';
return cypherText;
}
void InputInteger(int myInteger,char name [100])
{
printf("Input a number for %s : ",name);
scanf("%d", &myInteger);
}
void InputString(char myString[],char name[100])
{
printf("Input a string for %s : ",name);
scanf("%s", myString);
}
Is the problem with the allocation inside the function? Think it shouldn't be since I "copied" the cypher to the function return and then freed it. Thanks in advance!
The function call InputInteger(keySize,"key size"); cannot put a value to keySize. Both keySize and plainSize will remain as 0. So you are allocating 1 byte of memory for each string, only enough for a terminator. Computer melts.
I suggest these changes, firstly to pass back the input value
void InputInteger(int *myInteger, char name [100]) // add the *
{
printf("Input a number for %s : ", name);
scanf("%d", myInteger); // remove the &
}
then change the way you call it.
InputInteger(&keySize, "key size"); // add the &
InputInteger(&plainSize, "plaintext size"); // add the &
so that you pass the address of the variable you wish to alter.
Edit: That is not to say there are no other vulnerabilites in the code. The string length may be a negative number, you should be doing some input validation. Also the InputString function is open to malicious attack or accidental fault, where the user can say the string length is 2 and then wreck the stack, with some curious larger input which takes over the machine because it is executable code which the perp has placed there to steal your beans.

Dynamically prompt for string without knowing string size

In C, what is the best way of prompting and storing a string without wasted space if we cannot prompt for the string length. For example, normally I would do something like the following...
char fname[30];
char lname[30];
printf("Type first name:\n");
scanf("%s", fname);
printf("Type last name:\n");
scanf("%s", lname);
printf("Your name is: %s %s\n", fname, lname);
However, I'm annoyed with the fact that I have to use more space than needed so I do not want to use char fname[30], but instead dynamically allocate the size of the string. Any thoughts?
You can create a function that dynamically allocates memory for the input as the user types, using getchar() to read one character at a time.
#include <stdio.h>
#include <stdlib.h>
void* safeRealloc(void* ptr, size_t size) {
void *newPtr = realloc(ptr, size);
if (newPtr == NULL) { // if out of memory
free(ptr); // the memory block at ptr is not deallocated by realloc
}
return newPtr;
}
char* allocFromStdin(void) {
int size = 32; // initial str size to store input
char* str = malloc(size*sizeof(char));
if (str == NULL) {
return NULL; // out of memory
}
char c = '\0';
int i = 0;
do {
c = getchar();
if (c == '\r' || c == '\n') {
c = '\0'; // end str if user hits <enter>
}
if (i == size) {
size *= 2; // duplicate str size
str = safeRealloc(str, size*sizeof(char)); // and reallocate it
if (str == NULL) {
return NULL; // out of memory
}
}
str[i++] = c;
} while (c != '\0');
str = safeRealloc(str, i); // trim memory to the str content size
return str;
}
int main(void) {
puts("Type first name:\n");
char* fname = allocFromStdin();
puts("Type last name:\n");
char* lname = allocFromStdin();
printf("Your name is: %s %s\n", fname, lname);
free(fname); // free memory afterwards
free(lname); // for both pointers
return 0;
}
From man scanf:
• An optional 'm' character. This is used with string conversions (%s,
%c, %[), and relieves the caller of the need to allocate a
corresponding buffer to hold the input: instead, scanf() allocates a
buffer of sufficient size, and assigns the address of this buffer to
the corresponding pointer argument, which should be a pointer to a
char * variable (this variable does not need to be initialized before
the call). The caller should subsequently free(3) this buffer when it
is no longer required.
this however is a POSIX extension (as noted by fiddling_bits).
To be portable I think that in your usage case I would prepare a function like the following:
char *alloc_answer() {
char buf[1000];
fgets(buf,sizeof(buf),stdin);
size_t l = strlen(buf);
if (buf[l-1]=='\n') buf[l]=0; // remove possible trailing '\n'
return strdup(buf);
}
even if this solution will break lines longer than 1000 characters (but it prevents buffer overflow, at least).
A fully featured solution would need to read input in chunks and realloc the buffer on every chunk...

Searching and Reading a text file

this is my first time asking a question on here so I'll try to do my best. I'm not that great at C, I'm only in Intermediate C programming.
I'm trying to write a program that reads a file, which I got working. But I'm have search for a word then save the word after it into an array. What I have going right now is
for(x=0;x<=256;x++){
fscanf(file,"input %s",insouts[x][0]);
}
In the file there are lines that say "input A0;" and I want it to save "A0" to insouts[x][0]. 256 is just a number I picked because I don't know how many inputs it might have in the text file.
I have insouts declared as:
char * insouts[256][2];
Use fgets() & sscanf(). Seperate I/O from format scanning.
#define N (256)
char insouts[N][2+1]; // note: no * and 2nd dimension is 3
for(size_t x = 0; x < N; x++){
char buf[100];
if (fgets(buf, sizeof buf, stdin) == NULL) {
break; // I/O error or EOF
}
int n = 0;
// 2 this is the max length of characters for insouts[x]. A \0 is appended.
// [A-Za-z0-9] this is the set of legitimate characters for insouts
// %n record the offset of the scanning up to that point.
int result = sscanf(buf, "input %2[A-Za-z0-9]; %n", insouts[x], &n);
if ((result != 1) || (buf[n] != '\0')) {
; // format error
}
}
You want to pass the address of the x'th element of the array and not the value stored there. You can use the address-of operator & to do this.
I think
for(x = 0;x < 256; x++){
fscanf(file,"input %s", &insouts[x][0]);
// you could use insouts[x], which should be equivalent to &insouts[x][0]
}
would do the trick :)
Also, you are only allocating 2 bytes for every string. Keep in mind that strings need to be terminated by a null character, so you should change the array allocation to
char * insouts[256][3];
However, I'm pretty sure the %s will match A0; and not just A0, so you might need to account for this as well. You can use %c together with a width to read a given number of characters. However, you add to add the null byte yourself. This should work (not tested):
char* insouts[256][3];
for(x = 0; x < 256; x++) {
fscanf(file, "input %2c;", insouts[x]);
insouts[x][2] = '\0';
}
Rather than trying to use fscanf why don't you use "getdelim" with ';' as the delimiter.
According to the man page
" getdelim() works like getline(), except that a line delimiter other than newline can be specified as the delimiter argument. As with getline(), a delimiter character is not added if one was not present in the input before end of file was reached."
So you can do something like (untested and uncompiled code)
char *line = NULL;
size_t n, read;
int alloc = 100;
int lc = 0;
char ** buff = calloc(alloc, sizeof(char *)); // since you don't know the file size have 100 buffer and realloc if you need more
FILE *fp = fopen("FILE TO BE READ ", "r");
int deli = (int)';';
while ((read = getline(&line, &n, fp)) != -1) {
printf("%s", line); // This should have "input A0;"
// you can use either sscanf or strtok here and get A0 out
char *out = null ;
sscanf(line, "input %s;", &out);
if (lc > alloc) {
alloc = alloc + 50;
buff = (char **) realloc(buff, sizeof(char *) * alloc);
}
buff[lc++] = out
}
int i = 0 ;
for (i = 0 ; i < lc; i++)
printf ("%s\n", buff[i]);

menu function error: comparison between pointer and integer [enabled by default]

I have this function which is a menu. After compiling, the following error keeps showing up: error: comparison between pointer and integer [enabled by default]. why is this happening?
char choice;
printf ("Welcome to the Customer menu! \n");
printf ("Please select option from below\n");
printf ("a. Add customer\n");
printf ("b. Modify customer\n");
printf ("c. List customers\n");
printf ("d. Go back to main menu");
while ((gets(&choice)) != 'q')
{
if (choice == '\n')
continue;
switch (choice)
{
case 'a' : add_customer();
break;
case 'b' : printf ("products_main ()");
break;
case 'c' : printf ("orders_main ()");
break;
default : printf ("Invalid input. Please enter an option from the above menu\n");
continue;
}
printf ("END PROGRAM");
Thank you!!
The gets() function returns a char *, whereas you're comparing that return value to a char:
if (gets(&choice)) != 'q')
Also note that this is wrong in two levels, since gets() reads from stdin until it encounters a newline, so if you pass it the address of one char, it will likely cause a buffer overrun error. Why not use fgets() instead?
char buf[128];
fgets(buf, sizeof(buf), stdin);
if (buf[0] == 'q') {
/* etc */
}
You can't use gets() to do that, and afterall gets() is very dangerous, doesn't checks how much characters to read so can cause a very bad runtime buffer overflow.
You should use fgets() like H2CO3, it has a limit of characters to read, so is more secure.
char * input(const char *message, size_t quantity)
{
const int BUFFER_SIZE = 512;
char buf[BUFFER_SIZE], *res = NULL;
if(quantity > BUFFER_SIZE || quantity == 0)
quantity = BUFFER_SIZE - 1;
if(message)
printf("%s",message);
if(fgets(buf, quantity + 1, stdin) > 0)
{
char *end = strchr(buf, '\n');
if(end){
*end = '\0';
}
res = malloc(strlen(buf) + 1);
if(!res)
{
fprintf(stderr, "input(): MEM alloc error\n");
return NULL;
}
strcpy(res, buf);
}
return res;
}
Try with that function, just pass the message you want, and the exact quantity of characters of input that you want. :)
If you want to try it alone, here you have a test program:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char * input(const char *message, size_t quantity)
{
const int BUFFER_SIZE = 512;
char buf[BUFFER_SIZE], *res = NULL;
if(quantity > BUFFER_SIZE || quantity == 0)
quantity = BUFFER_SIZE - 1;
if(message)
printf("%s",message);
if(fgets(buf, quantity + 1, stdin) > 0)
{
char *end = strchr(buf, '\n');
if(end){
*end = '\0';
}
res = malloc(strlen(buf) + 1);
if(!res)
{
fprintf(stderr, "input(): MEM alloc error\n");
return NULL;
}
strcpy(res, buf);
}
return res;
}
int main()
{
char *a = input("Input:", 4);
if(a)
{
printf("%s\n",a);
free(a);
return 0;
}
printf("Got NULL input\n");
return -1;
}
When you have a doubt about a particular function, what are their arguments, their return value, you could look it up in Google, and you will find plenty of examples and the function definition. With the time you will learn to easily understand the definitions and memorize some function names and their parameters.
Good Luck!
This line:
while ((gets(&choice)) != 'q')
gets() reads a string, not a char, and returns that string (i.e. it fills a buffer you pass to it via the char pointer). You then compare the pointer returned (which is the same as the one you passed in) with a char.
You probably just want to read a single character. If you want a whole string, you need to read it into a char array, and not pass the address of a single char.
After doing some reading I found that including
#include <unistd.h>
helps get ride of the warning. I'm new to unix c and I've never seen it before. I'm also still testing my code so I'll get back to you when I figure out if this works or not.
Hope this helps.
In the end the warning came back and it ended up going in an infinite loop so something is wrong with my logic.
Sorry I wasn't any help.

Resources