I am trying to allocate a dynamic array of Country objects for my school project. I have malloc'd the array in main() function and I am reallocating it in a add_country() function. but it seems to give me realloc invalid ponter error. Could someone help? This is the minimal reproducable code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int count = 0;
typedef struct test_Country
{
char name[20];
int gold;
int silver;
int bronze;
} test_Country;
test_Country *addtest_Country(test_Country test_Country_obj, test_Country*array)
{
int flag = 0;
printf("%s\n", "before realloc");
test_Country *new_array;
new_array = realloc(array, sizeof(test_Country *) * (count + 1));
printf("%s\n", "after realloc");
//array[count].name = (char *)malloc(strlen(test_Country_obj.name) + 1);
if (count == 0)
{
strcpy(new_array[0].name, test_Country_obj.name);
}
else
{
for (int i = 0; i < count; i++)
{
if (strcasecmp(new_array[i].name, test_Country_obj.name) == 0)
{
printf("%s", "test_Country already added\n");
flag = 1;
break;
}
}
}
if (flag == 0)
{
strcpy(new_array[count].name, test_Country_obj.name);
test_Country_obj.gold = 0;
test_Country_obj.silver = 0;
test_Country_obj.bronze = 0;
new_array[count] = test_Country_obj;
count = count + 1;
}
flag = 0;
return new_array;
}
int main()
{
char choice;
test_Country *array = malloc(sizeof(test_Country));
test_Country test_Country_obj;
printf("%s", "Enter your choice : ");
scanf("%s", &choice);
//fgets(ptr, 80, stdin);
//sscanf(ptr, "%c %s %d %d %d", &choice, test_Country_obj.name, &test_Country_obj.gold, &test_Country_obj.silver, &test_Country_obj.bronze);
//printf("%s", &choice);
while (choice != 'E')
{
printf("%s", "Enter test_Country name : ");
scanf("%s", test_Country_obj.name);
array = addtest_Country(test_Country_obj, array);
//printf("%d%s", count, "is count");
printf("%s", "Enter your choice : ");
scanf("%s", &choice);
}
}
I cant seem to understand what is wrong.
char choice;
scanf("%s", &choice);
is bad. choice has only room for one character, so it can hold only strings upto zero characters. (the one-character room is for terminating null-character). Trying to store strings longer than zero character leads to dangerous out-of-range write and it may destroy data around that.
To avoid out-of-range write, you should allocate enough elements and specify the maximum length to read. The maximum length should be the buffer size minus one for terminating null-character.
char choice[16]; /* allocate enough elements */
scanf("%15s", choice); /* specify the maximum length */
After that, choice in the while and switch should be replaced with choice[0] to judge by the first character. Another way is using strcmp() to check the whole string.
Related
I want my user to enter the input which I have set only for each and every declaration, but when I tried running the program it still proceeds, for example, name the ic_size the limit character is only 12 character input, but if I put more than 12 it just accepts it as nothing wrong. Here's the coding I tried:
void login_register()
{
const name_size = 80;
char name[name_size];
const ic_size = 12;
char ic[ic_size];
const no_size = 12;
char no[no_size];
const nationality_size = 20;
char nationality[nationality_size];
const email_size = 50;
char email[email_size];
int select;
int Day =0;
int bed_tax =0;
double RM;
double room_price=0;
double service_tax = 0;
double total = 0;
char term,check;
printf("\n Please enter your name : ");
while(gets(name))/* same as scanf ("%s",name) %s mean print the corresponding argument in string*/
{
if(!isalpha && sizeof(name) > name_size) // restrict user input can only be alphabeth and must not exceed array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your IC number : ");
while(gets(ic))
{
if(isdigit && sizeof(ic) < ic_size) // restrict user input can only be numerical and must not excedd array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your phone number : ");
while(gets(no))
{
if(isdigit && sizeof(no) < no_size)
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your nationality : ");
while(gets(nationality))/* same as scanf ("%s",nationality) %s mean print the corresponding argument in string*/
{
if(!isalpha && sizeof(nationality) > nationality_size) // restrict user input can only be alphabeth and must not exceed array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your email : ");
while(gets(email))/* same as scanf ("%s",email) %s mean print the corresponding argument in string*/
{
if(!isalpha && sizeof(email) > email_size) // restrict user input can only be alphabeth and must not exceed array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
Rather than gets(), which has no limit on user input, consider fgets().
Shift design goal to:
Allow unlimited input per line, but only save up to N characters of input.
Let user know if too much entered. Try again if needed.
I recommend a helper function that prompts, reads input, and handles long lines.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// 'size' is the size of the array 'destination' points to.
int get_user_input(const char *prompt, size_t size, char *destination) {
char buf[size + 2]; // size + \n + 1 extra
do {
fputs(prompt, stdout);
if (fgets(buf, sizeof buf, stdin) == NULL) {
*destination = '\0';
return 0; // End of file
}
char *end_of_line = strchr(buf, '\n');
if (end_of_line) {
*end_of_line = '\0'; // Lop off \n
} else {
// get rest of line
scanf("%*[^\n]"); // Read everything up to a \n and toss
scanf("%*1[\n]"); // Read a \n and toss
}
} while (strlen(buf) >= size);
strcpy(destination, buf);
return 1;
}
Now read as needed. Recall that name_size = 12 means up to 11 characters are saved as 1 more is needed to save the null character. Adjust name_size as needed.
int main(void) {
const int name_size = 12;
char name[name_size];
const int nationality_size = 20;
char nationality[nationality_size];
get_user_input("Please enter your name: ", sizeof name, name);
printf("Name <%s>\n", name);
get_user_input("Please enter your nationality: ", sizeof nationality, nationality);
printf("Nationality <%s>\n", nationality);
}
My code provides the following parameters requested by the teacher:
But the teacher also wants this: "insertChar function should not overwrite any characters. It should insert the new character and offset remaining characters by one index."
how can I set this up? I mean how can I shift a string right from a certain point?
#include<stdio.h>
#include<string.h>
void insertChar(char string[], char c, int index) {
int len = 0;
int i;
for (i = 0; i > index; i--) {
string[i] = len;
string[i] = string[i-1];
string[i-1] = len;
}
string[index] = c;
}
int main() {
char string[100];
printf("Please input a string \n");
scanf ("%[^\n]%*c", string);
printf("Please input the character to be added to string.\n");
char c;
scanf ("%c", &c);
printf("Please input the index which the function will insert the character. \n");
int index;
scanf("%d", &index);
insertChar(string, c, index);
printf("%s", &string);
return 0;
}
How can I shift right after a certain point in the string?
(OP's insertChar() is too broken for repair.)
Watch out for 2 pitfalls: inserting well past the end of the string and exceeding the size of the buffer:
#include <string.h>
void insertChar(size_t buffer_size, char string[], char c, size_t index) {
size_t size_used = strlen(string) + 1;
if (size_used >= buffer_size) {
fprintf(stderr, "Buffer too small for insertion or existing string.");
} else if (index >= size_used) {
fprintf(stderr, "Inserting well past the end of the string.");
} else {
// Move the right portion of the string by 1 with memmove
// v----------------v Address one past the insertion point
memmove(&string[index + 1], &string[index], size_used - index);
// ^------------^ Insertion location
string[index] = c; // Insert
}
}
Usage
char string[100];
...
insertChar(sizeof string, string, c, index);
I have been looking at this code of mine for my schoolwork but I cannot understand why my integer variable has changed after I passed it into a function by value although I did not alter it in the function.
#include <stdio.h>
#include <stdlib.h>
void Q1();
void Q1_Remove (char **ptr_string);
void Q1_Insert (char **ptr_string, int length);
int main()
{
Q1();
return 0;
}
void Q1 () {
int number;
printf("How many characters do you want to input: ");
scanf("%d", &number);
char *string = malloc(number + 1);
printf("Input the string: ");
scanf("%s", string);
printf("The string is: %s\n", string);
int option;
do {
printf("Do you want to 1-Insert, 2-Remove or 3-Quit: ");
scanf("%d", &option);
switch (option) {
case 1:
Q1_Insert(&string, number);
break;
case 2:
Q1_Remove(&string);
break;
}
if (option == 1 || option == 2) {
printf("Resulting string: %s\n", string);
}
} while (option == 1 || option == 2);
free(string);
}
void Q1_Remove (char **ptr_string) {
(*ptr_string)++;
}
void Q1_Insert (char **ptr_string, int length) {
int curr_len = strlen(*ptr_string);
int i;
printf("length is %d and curr_len is %d", length, curr_len);
if (curr_len == length) {
for (i = curr_len - 1; i > 0; --i) {
*(ptr_string + i) = *(ptr_string + i - 1);
}
} else {
(*ptr_string)--;
}
char to_insert;
printf("What is the character you want to insert: ");
scanf(" %c", &to_insert);
**ptr_string = to_insert;
}
My terminal input and output:
How many characters do you want to input: 5
Input the string: abcde
The string is: abcde
Do you want to 1-Insert, 2-Remove or 3-Quit: 1
length is 5 and curr_len is 5
What is the character you want to insert: a
Resulting string: abcde
Do you want to 1-Insert, 2-Remove or 3-Quit: 1
length is 11212224 and curr_len is 5 // length is weird here
What is the character you want to insert:
(EDIT 2)
Removed constant for variable number and added in the declaration on the top. Edited to add in the headers!
Primarily the issue is how you are shuffling characters in the string. You are doing this:
for (i = curr_len - 1; i > 0; --i) {
*(ptr_string + i) = *(ptr_string + i - 1);
}
However, the actual string pointer is *ptr_string. Since you are using ptr_string + i, it's treating ptr_string as an array of pointers, and you are writing all over the stack memory following your string pointer defined in main. This will be what is trashing your number value, among other things.
Instead, you need to do this:
*(*ptr_string + i) = *(*ptr_string + i - 1);
Personally, I'd use array notation instead, which is far more readable:
(*ptr_string)[i] = (*ptr_string)[i - 1];
Or simply scrap the loop entirely and use memmove.
I'm working in a problem from the "C programming a Modern Approach 2nd Edition" text. I want to write a program that writes the smallest and largest words. The program stops accepting inputs when the user enters a 4-letter word.
I'm using an array of strings to solve this but I can't even get my program to store words in it.
#include <stdio.h>
#include <string.h>
#define WORD_LEN 20
int main()
{
char word[WORD_LEN]={0},ch;
char *a[10]={}; //Max 10 words in the array
int i=0,j;
for(;;)
{
printf("Enter a word: ");
fgets(word,WORD_LEN,stdin);
strtok(word, "\n"); //removes newline
a[i] = word;
if(strlen(word) == 4) //if word is 4 characters
break; //break out of loop
i++;
}
for(j=0;j<i;j++) //displaying array
printf("%s\n",a[j]);
return 0;
}
Output:
Enter a word: Analysis
Enter a word: Martin
Enter a word: Jonathan
Enter a word: Dana
Dana
Dana
Dana
Any idea into what I'm doing wrong? Thanks.
As BLUEPIXY mentioned, you are storing same address in all a[i]s. So at the end of the loop, it prints the last output i times.
Solution:
You need to allocate memory for a[i] and copy the strings.
#include <stdio.h>
#include <string.h>
#define WORD_LEN 20
#define MAX_NUM_WORD 10 //Max 10 words in the array
int main()
{
char word[WORD_LEN]={0},ch;
char *a[MAX_NUM_WORD]={0};
int i=0,j;
for(;;)
{
printf("Enter a word: ");
fgets(word,WORD_LEN,stdin);
strtok(word, "\n"); //removes newline
a[i] = malloc(sizeof(char)* (strlen(word)+1)); //1 for '\0'
strcpy(a[i], word);
i++;
if(strlen(word) == 4) //if word is 4 characters
break; //break out of loop
//i++; //You will be missing last 4 letter word if i++ is here.
if(MAX_NUM_WORD <= i) //You can store only MAX_NUM_WORD strings
break;
}
for(j=0;j<i;j++) //displaying array
printf("%s\n",a[j]);
//Your other code.
for(i=0; i<MAX_NUM_WORD && NULL != a[i]; i++)
free(a[i]); //Free the allocated memory.
return 0;
}
Adding to others answers, when using malloc to allocate memory for your strings, it is good to also check the return value of void* pointer returned from it.
Additionally, it is also safe to check the return value of fgets, just to be super safe.
This solution demonstrates these points:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LEN 20
#define MAX_NUM_WORD 10
#define EXIT_LEN 4
int
main(void) {
char word[WORD_LEN];
char *a[MAX_NUM_WORD];
int i = 0, wrd;
while (i < MAX_NUM_WORD) {
printf("Enter a word: ");
if (fgets(word, WORD_LEN, stdin) != NULL) {
word[strlen(word)-1] = '\0';
}
a[i] = malloc(strlen(word)+1);
if (a[i] == NULL) {
fprintf(stderr, "%s\n", "Malloc Problem");
exit(EXIT_FAILURE);
}
strcpy(a[i], word);
i++;
if (strlen(word) == EXIT_LEN) {
break;
}
}
// Print and free, all at once.
for (wrd = 0; wrd < i; wrd++) {
printf("%s\n", a[wrd]);
free(a[wrd]);
a[wrd] = NULL;
}
return 0;
}
I want to run this code but i can not. i have yet started to learn pointer in C. I am trying to get the addresses of letters. Problem is printf("in adress: %p\n",p[i]);` Thanks
#include <stdio.h>
int main(void){
char letter;
int c=0;
int i;
char pattern[7];
char *p;
printf("Enter a letter: ");
scanf("%c",&letter);
printf("Enter a pattern: ");
scanf("%s",pattern);
p=pattern;
for(i=0;i<7;i++)
{
if(letter==pattern[i])
{
c++;
printf("Letter < %c > is found in pattern %s\n",letter,pattern);
printf("in adress: %p\n",p[i]);
printf("index:%d\n",i);
}
}
if(c==0)
printf("The pattern does not include any letter");
return 0;
}
This line of code has some potential problem that can easily happen
scanf("%s",&pattern);
you can make it a little bit safer like this
scanf("%6s",&pattern);
it's a 6 because you need one extra byte '\0' at the end of the string, which takes us to the next problem
for(i=0;i<7;i++)
here you are assuming that all bytes are non-nul which would be ok except that you are reading a string with scanf() and unless you create the array one byte bigger than the number of characters you want to store in it, scanf() will overflow the array i.e. write a byte beyond it's bounds.
Adding the "%6s" length specifier to the format string solves this, but you can only store 6 non-nul bytes in the array, and for the other problem
for (i = 0 ; pattern[i] != '\0' ; i++)
would be better, because you don't need to know the length of the string in advance and you don't risk reading past the end of the array.
Try this:
#include <stdio.h>
int main(void)
{
char letter;
char c;
int i;
char pattern[7];
printf("Enter a letter: ");
if (scanf(" %c",&letter) != 1)
{
printf("error: invalid input.\n");
return -1;
}
printf("Enter a pattern: ");
if (fgets(pattern, sizeof(pattern), stdin) == NULL)
{
printf("error: end of file.\n");
return -1;
}
for (i = 0 ; pattern[i] != 0 ; ++i)
{
if (letter == pattern[i])
{
c++;
printf("Letter < %c > is found in pattern %s\n", letter, pattern);
printf("in adress: %p\n", pattern + i);
printf("index :%d\n", i);
}
}
if (c == 0)
printf("The pattern does not include any letter");
return 0;
}
You also was printg the address wrong, because in pointer[i] the subscript operator dereferences the pointer, it's equivalent to *(poitner + i).