I am programming a registration system using array strings for postal code and home address. I use a constant to determine the postal code limit of just 8 characters.
When the program start the register function, it makes the address and postal code inputs correct, but when I list it, the address appears normal and the postal code of position 1 together with the others below. Why is this happening? I put 8 character positions for the postal code and it increases by placing the second one as well.
My program:
#include <stdio.h>
#define LIMIT_POSTAL 8
#define LIMIT_REGISTER 5
#define LIMIT_ADDRESS 20
char postal_c[LIMIT_REGISTER][LIMIT_POSTAL], address[LIMIT_REGISTER][LIMIT_ADDRESS];
int line;
void reg()
{
int op;
do
{
printf("Address: ");
scanf("%s", &address[line]);
printf("Postal code: ");
scanf("%s", &postal_c[line]);
op = -1;
printf("1 - Continue\nAny number - Exit\n");
scanf("%d", &op);
line++;
} while(op == 1);
}
int main()
{
int i;
reg();
for(i = 0; i < line; i++)
{
printf("Address: %s\n", address[i]);
printf("Postal: %s\n", postal_c[i]);
}
return 0;
}
Output:
Address: foo
Postal code: 11111111
1 - Continue
Any number - Exit
1
Address: foo2
Postal code: 22222222
1 - Continue
Any number - Exit
0
Address: foo
Postal: 1111111122222222
Address: foo2
Postal: 22222222
In your code probably:
#include <stdio.h>
#define LIMIT_POSTAL 8
#define LIMIT_REGISTER 5
#define LIMIT_ADDRESS 20
char postal_c[LIMIT_REGISTER][LIMIT_POSTAL], address[LIMIT_REGISTER][LIMIT_ADDRESS];
int line;
void reg()
{
int op;
do
{
printf("Address: ");
scanf("%s", &address[line]);
printf("Postal code: ");
scanf("%s", &postal_c[line]);
op = -1;
printf("1 - Continue\nAny number - Exit\n");
scanf("%d", &op);
line++;
} while(op == 1);
}
int main()
{
int i;
reg();
for(i = 0; i < line; i++)
{
printf("Address: %s\n", address[i]);
printf("Postal: %s\n", postal_c[i]);
}
return 0;
}
I can't see you had initialized line variable in you program and you are using it directly to pointing the index, hence you didn't assigned any value so probably it contains garbage value and pointing invalid memory address in your program.
I am assuming your rest code is correct.
try doing...
int line =0;
Related
This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 1 year ago.
I have written a program which makes use of array of structures in order to maintain a sort of "database" program with different options that can be used to manipulate the "database".
The program has 4 modes of operation, if the user enters:
'i' data can be inserted into the "database".
's' searches the "database" for a part with a part number of a item.
'u' updates something in the database based on the part number of a item.
'p' prints the whole "database".
Here is the code which is made of 3 files:
database.h:
#ifndef DATABASE
#define DATABASE
struct db
{
int part_number;
char *part_name;
int part_quantity;
};
extern struct db database[50];
extern void insert(int i);
extern int search(int i);
extern int update(int i);
extern int print(int i);
#endif
database.c
#include <string.h>
#include <stdio.h>
#include "database.h"
struct db database[50];
void insert(int i)
{
char name_of_part[21], c;
printf("%p\n", &database[i].part_name);
printf("\n");
printf("Enter a part number: ");
scanf("%d", &database[i].part_number);
while((c = getchar()) != '\n' && c != EOF); // flush stdin
printf("Enter a part name: ");
fgets(name_of_part, 20, stdin);
printf("Enter quantity of part: ");
scanf("%d", &database[i].part_quantity);
database[i].part_name = name_of_part;
printf("\n");
}
int search(int i)
{
int input;
printf("\n");
printf("Enter a part number: ");
scanf("%d", &input);
for (int j = 0; j <= i; j++)
{
if (database[j].part_number == input)
{
printf("Part name: %s\n", database[j].part_name);
printf("Quantity on hand: %d\n", database[j].part_quantity);
return 0;
}
}
printf("Part not found.\n");
}
int update(int i)
{
int input, quantity;
printf("\n");
printf("Enter part number: ");
scanf("%d", &input);
for (int j = 0; j <= i; j++)
{
if (database[j].part_number == input)
{
printf("Enter part quantity: ");
scanf("%d", &quantity);
database[j].part_quantity = quantity;
return 0;
}
}
printf("Part number not found.");
}
int print(int i)
{
for (int j = 0; j < i; j++)
{
printf("Part number: %d\n Part name: %s\n Part quantity: %d\n", database[j].part_number, database[j].part_name,database[j].part_quantity);
}
}
main.c
#include <stdio.h>
#include <string.h>
#include "database.h"
int main()
{
int i = 0;
char code;
while (1)
{
printf("Enter a function code: ");
scanf(" %c", &code);
switch (code)
{
case 'i':
insert(i);
i += 1;
break;
case 's':
search(i);
break;
case 'u':
update(i);
break;
case 'p':
print(i);
break;
}
}
return 0;
}
The problem i have is that when i insert into the "database", the name in each structure gets overwritten. for example:
Enter a function code: i
Enter a part number: 111
Enter a part name: 111
Enter quantity of part: 111
Enter a function code: i
Enter a part number: 222
Enter a part name: 222
Enter quantity of part: 222
Enter a function code: p
Part number: 111
Part name: 222
Part quantity: 111
Part number: 222
Part name: 222
Part quantity: 222
Enter a function code:
As you can see first i insert something new in the "database", take note of the "Part name" which is "111".
Next i insert something else into the database
this time the "Part name" is "222".
Lastly i print the whole "database" what i am confused about is why the part name has now overlapped. but why is this? all the other members such as the part_number and part_quantity remain intact in both insert operations so why does char *part_name stay the same ? and how do i fix this ?
You have the part_name member declared as a char * and you assign to it the address of a local array in the insert function. When the function returns, that array goes out of scope and the stored pointer becomes invalid. Subsequently trying to use that pointer triggers undefined behavior.
Change part_name to be an array:
struct db
{
int part_number;
char part_name[21];
int part_quantity;
};
And write directly to that:
printf("Enter a part name: ");
fgets(database[i].part_name, 21, stdin);
The line
database[i].part_name = name_of_part;
is bad. This is assigning a pointer to the non-static local variable. The variable ends its life on returning from the function and dereferencing pointers pointing to that is illegal.
Instaed of this, you have to copy the string. If you system supports strdup(), it can be done like this:
database[i].part_name = strdup(name_of_part);
If strdup() is not supported or you want to stick to the standard, you dan do like this:
database[i].part_name = malloc(strlen(name_of_part) + 1); /* +1 for ther terminating null-character */
if (database[i].part_name != NULL)
{
strcpy(database[i].part_name, name_of_part);
}
Add #include <stdlib.h> to use malloc().
I'm just trying to write a simple code where I enter a 3 letter word and then print out the word I entered. I tried doing this by creating the array, and then making a loop where the counter "i" keeps incrementing and the scan function keeps working for each index value of the letter I add.
But there seems to be some error in line 16, and even then not sure if the logic of the code is right.
#include <string.h>
#define ALEN 3
int main (void)
{
char array[ALEN];
int i;
printf("Enter a 3 letter word> ");
scanf("%s", array);
for(i=0; i<ALEN; i++)
{
array[i] = array[ALEN];
scanf("%s", &array[i]);
}
printf("\n");
printf("Word entered: %s", char array[i]);
return 0;
}```
I'm trying to write a program that finds the "greatest" and "smallest" between a set of words inputted by the user. The program should stop listening for words assign as the user inputs a 4 letters long word and I can suppose that there aren't any words longer than 20 letters.
Here's how it should work:
Enter word: dog
Enter word: zebra
Enter word: rabbit
Enter word: catfish
Enter word: walrus
Enter word: cat
Enter word: fish
Smallest word: cat
Largest word: zebra
I tried debugging the code and I noticed that my function only runs the first "if" twice (until zebra is inputted) and then stops working. I don't really get why, every word there is smaller than zebra so it should always run. Also I don't get why the second "if" doesn't run.
Here's my code:
#include <stdio.h>
#include <string.h>
#define N 20
int read_line(char smallest[], char largest[]);
int main(){
char smallest[N], largest[N];
int check = 0;
while(check != 4){
check = read_line(smallest, largest);
}
printf("Smallest word: %s\n", smallest);
printf("Largest word: %s\n", largest);
return 0;
}
int read_line(char smallest[], char largest[]){
char input[N];
printf("Enter word: ");
scanf("%s", input);
if(strcmp(smallest, input) < 0){
printf("Smallest is: %s was: %s\n", input, smallest);
strcpy(smallest, input);
}
if(strcmp(largest, input) > 0){
printf("Largest is: %s was: %s\n", input, largest);
strcpy(largest, input);
}
return strlen(input);
}
As others have pointed out there might be a problem initialization. Since the array is not initialized you don't know what's there that's why a comment was saying it is generating an undefined behaviour. In my case I run your original code inputting twice and even after zebra it continued. Anyway is always better to initialize.
Just put a scanf outside the loop and initialize both values to the first input:
EDIT
I did not pay attention to strcmp usage because the main problem seemed to be the initalization.
From your code and comment it is clear that you are also messing with strcmp. You should have read the documentation:
int strcmp(const char *s1, const char *s2);
Upon completion, strcmp() shall return an integer greater than, equal
to, or less than 0, if the string pointed to by s1 is greater than,
equal to, or less than the string pointed to by s2, respectively.
So strcmp(smallest, input) ) returns a value < 0 if smallest is less (before in the dictionary pages to be clear) than input. You should change to if(strcmp(smallest, input) > 0) meaning smallest is greater than input or to if(strcmp(input, smallest) < 0)
strcmp(largest, input) returns > 0 if largest is bigger than input. Your condition strcmp(largest, input) > 0 is wrong. You want the opposite: you can invert the comparison: strcmp(largest, input) < 0 or invert the inputs: strcmp(input, largest) > 0.
#include <stdio.h>
#include <string.h>
#define N 21
int read_line(char smallest[], char largest[]);
int main(){
char smallest[N];
char largest[N];
int check = 0;
char firstInput[N];
printf("Enter word: ");
scanf("%s", firstInput);
printf("Smallest and largest initialized to: %s\n", firstInput);
strcpy(smallest, firstInput);
strcpy(largest, firstInput);
while(check != 4){
check = read_line(smallest, largest);
}
printf("Smallest word: %s\n", smallest);
printf("Largest word: %s\n", largest);
return 0;
}
int read_line(char smallest[], char largest[]){
char input[N];
printf("Enter word: ");
scanf("%s", input);
if(strcmp(smallest, input) < 0){
printf("Smallest is: %s was: %s\n", input, smallest);
strcpy(smallest, input);
}
if(strcmp(largest, input) > 0){
printf("Largest is: %s was: %s\n", input, largest);
strcpy(largest, input);
}
return strlen(input);
}
In my opinion this is the clearer initialization (and more correct) since it uses user's input and does not rely on any condition. However the code is less compact than other possible initializations since you are repeating some part of the code.
EDIT alternative initializations
There are other initialization methods. One is to initialize for example to the lowest letter:
char smallest[N];
for (int i=0; i<N-1; i++)
{
smallest[i] = 'z' ;
}
smallest[N-1] = '\0';
char biggest[N];
for (int i=0; i<N-1; i++)
{
biggest[i] = 'a' ;
}
biggest[N-1] = '\0';
In your original code this will print something like zzzzz.... and aaaa....
Another alternative is to initialize them to the numerical min and max values of the range of char types (typically -128 and 127):
#include<math.h>
...
char smallest[N] ;
char biggest[N] ;
for (int i=0; i<N-1; i++)
{
smallest[i] = (char) (pow(2,sizeof(char)*8)/2 - 1);
}
smallest[N-1] = '\0';
for (int i=0; i<N-1; i++)
{
biggest[i] = (char) -1*(pow(2,sizeof(char)*8)/2);
}
biggest[N-1] = '\0';
However in case in your first print will print thrash (better not to print at all ).
EDIT FOR scanf alternatives
When a user is inputting anything, especially a string, it is a good behaviour to test if that input conforms to what you are expecting. In C this becomes even more important since inputting a string longer than the length (actually length-1) of the array in which the string will be stored will cause Segmentation fault error and the program crashes.
There is a simple way to avoid this: instead of scanf("%s", firstInput); do, in your specific case, scanf("%20s", firstInput); i.e. the length of your input array minus 1 (N-1). The problem with this approach is that you cannot use a dynamic value: for example:
#define M 20
scanf("%Ms", firstInput);
does not work.
According to this post you could:
#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x
{
...
char word[MAX_STRING_LENGTH+1];
scanf(file, "%" STRINGIFY(MAX_STRING_LENGTH) "s", word);
...
}
or follow the approach of this post:
int scanner(const char *data, char *buffer, size_t buflen)
{
char format[32];
if (buflen == 0)
return 0;
snprintf(format, sizeof(format), "%%%ds", (int)(buflen-1));
return sscanf(data, format, buffer);
}
NOTE
If you mix words with and without capital letters, the ordering might not work anymore: Zookeeper (fantastic animal) comes before antilope.
Ok, there are multiple flaws in your program:
First of all, as other answers pointed out, you should #define N as 21, not 20, so as to leave room for the null character.
Secondly, you should initialize your strings.
And, most importantly, you have messed the order of your strcmp arguments. You should either pass first input and then the string you want to compare to, or change the inequality signs.
Finally, you should initialize largest as "" so that the first character equals zero and so the string is smaller than all possible strings. And you should initialize smallest to the largest possible string (e.g. "\xFF", although that will not work if the input string starts with the non-ASCII character '\xFF'). Then, when you enter the first string, it will be copied over both buffers. However, you'd better set a variable to check for the first input string given, and add a condition to copy it to both largest and smallest. This is slightly more complex, but works with all strings.
Here is your updated code:
#include <stdio.h>
#include <string.h>
#define N 21
int read_line(char smallest[], char largest[]);
int not_first = 0;
int main(){
char smallest[N], largest[N];
int check = 0;
while(check != 4){
check = read_line(smallest, largest);
}
printf("Smallest word: %s\n", smallest);
printf("Largest word: %s\n", largest);
return 0;
}
int read_line(char smallest[], char largest[]){
char input[N];
printf("Enter word: ");
scanf("%s", input);
if(strcmp(input, smallest) < 0 || !not_first){
printf("Smallest is: %s was: %s\n", input, (not_first)? smallest : "(none)");
strcpy(smallest, input);
}
if(strcmp(input, largest) > 0 || !not_first){
printf("Largest is: %s was: %s\n", input, (not_first)? largest : "(none)");
strcpy(largest, input);
}
not_first = 1;
return strlen(input);
}
I have got this template.
#include <stdio.h>
#include <string.h>
#define SIZE 10
int findTarget(char *target, char nameptr[SIZE][80], int size);
int main()
{
char nameptr[SIZE][80];
char t[40];
int i, result, size;
printf("Enter no. of names: ");
scanf("%d", &size);
printf("Enter %d names: ", size);
for (i = 0; i<size; i++)
scanf("%s", nameptr[i]);
printf("Enter target name: ");
scanf("\n");
gets(t);
result = findTarget(t, nameptr, size);
printf("findTarget(): %d\n", result);
return 0;
}
int findTarget(char *target, char nameptr[SIZE][80], int size)
{
/* write your code here */
int i;
for (i = 0; i < size; i++) {
if (nameptr[i] == *target)
return i;
}
return -1;
}
And the code under /* write your code here */ is my code.
The code doesn't work. I think something is wrong with (nameptr[i] == *target).
Examples of output:
Enter no. of names: 4
Enter 4 names: Peter Paul John Mary
Enter target name: John
findTarget(): 2
Enter no. of names: 4
Enter 4 names: peter mary john steve
Enter target name: may
findTarget(): -1
I think the template is correct cos its provided by school.
Thank you for helps.
This:
if (nameptr[i] == *target)
is wrong because you are comparing a pointer with an integer and that makes no sense. Also, in order to compare two strings, use strcmp. Using == will compare the pointers and not the content of them.
Fix:
if (strcmp(nameptr[i], target) == 0)
I cannot seem to output a string or an integer array correctly in C programming.
My issue, is that the strings are stored in the array, I just cannot get them OUT of the array and to the output.
When I manually enter the positions (like Array[0]), it properly outputs.
However, the final loop fails to output any of my array entries.
Why is this happening?
Thanks in advance for all replies!
Here is the code:
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
main (void)
{
int memory_start;
int memory_end;
int num_jobs;
printf("Enter the starting memory location to be used : ");
scanf("%d", &memory_start);
printf("\nEnter the ending memory location to be used : ");
scanf("%d", &memory_end);
printf("\nHow many jobs will be assigned to the memory locations? \n");
scanf("%d", &num_jobs);
int mem_size = memory_end - memory_start;
int mem_size_init = memory_end - memory_start;
char names[10][20];
int sizes[num_jobs];
int mem_st[10];
int mem_end[10];
int x;
int y;
int z;
int temp_size = 0;
int prev_temp_size;
char temp_name[20];
for(x=0; x<num_jobs; x++)
{
prev_temp_size = prev_temp_size + temp_size;
printf("\nEnter the size of the program (size > 0): ");
scanf("%d", &temp_size);
if( mem_size >= temp_size && temp_size > 0)
{
printf("\nEnter a program name (20 chars): %s", names[1]);
scanf("%s", &temp_name);
if(strlen(temp_name) <= 20)
{
strcpy(names[x], temp_name);
// names[x] = temp_name;
sizes[x] = temp_size;
mem_size = mem_size - temp_size;
mem_st[x] = prev_temp_size + memory_start;
mem_end[x] = temp_size + mem_st[x];
}
else
{
printf("\nProgram name is too long. Please re enter data.");
x--;
}
}
else
{
printf("\nMemory Size not supported (not enough space remaining).\nPlease re-enter data with a plausible memory request.");
printf("\nMemory size remaining: %d", mem_size);
x--;
}
}
printf("\nYour data is as follows: \n");
printf("\nYour initial memory size is: %d", mem_size_init);
printf("\nYour unused memory size is: %d", mem_size);
for(y=0; y<num_jobs; y++)
{
printf("Program: %s", names[y]);
printf("\n", names[y], " memory size is as follows: \n", "memory start: %d", mem_st[y], " memory end: %d", mem_end[y]);
}
}
Here is the corrected code:
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
main (void)
{
int memory_start;
int memory_end;
int num_jobs;
printf("Enter the starting memory location to be used : ");
scanf("%d", &memory_start);
printf("\nEnter the ending memory location to be used : ");
scanf("%d", &memory_end);
printf("\nHow many jobs will be assigned to the memory locations? ");
scanf("%d", &num_jobs);
int mem_size = memory_end - memory_start;
int mem_size_init = memory_end - memory_start;
char names[10][20];
int sizes[num_jobs];
int mem_st[10];
int mem_end[10];
int x;
int y;
int z;
int temp_size = 0;
int prev_temp_size;
char temp_name[20];
for(x=0; x<num_jobs; x++)
{
prev_temp_size = prev_temp_size + temp_size;
printf("\nEnter the size of the program (size > 0): ");
scanf("%d", &temp_size);
if( mem_size >= temp_size && temp_size > 0)
{
printf("\nEnter a program name (20 chars): ");
scanf("%s", temp_name);
getchar();
if(strlen(temp_name) <= 20)
{
strcpy(names[x], temp_name);
sizes[x] = temp_size;
mem_size = mem_size - temp_size;
mem_st[x] = prev_temp_size + memory_start;
mem_end[x] = temp_size + mem_st[x];
}
else
{
printf("\nProgram name is too long. Please re enter data.");
x--;
}
}
else
{
printf("\nMemory Size not supported (not enough space remaining).\nPlease re-enter data with a plausible memory request.");
printf("\nMemory size remaining: %d", mem_size);
x--;
}
}
printf("\nYour data is as follows: \n");
printf("\nYour initial memory size is: %d", mem_size_init);
printf("\nYour unused memory size is: %d\n", mem_size);
for(y=0; y<num_jobs; y++)
{
printf("\nProgram: %s\n", names[y]);
printf("\nmemory size is as follows:\nmemory start: %d memory end: %d\n", mem_st[y], mem_end[y]);
}
}
Apart from changes in formatting the output, major changes are:
Removed the & in scanf("%s", &temp_name); because, the name of an array already returns a reference to its first element.
Added a getchar(); after scanf("%s", temp_name); because after reading in a string an extra \n remains in the stream, which causes the next scanf to fail.
This:
printf("\n", names[y], " memory size is as follows: \n", "memory start: %d", mem_st[y], " memory end: %d", mem_end[y]);
is not how a format specifier is prepared, all variables need to be placed at the end, after a single format specifier string.
The last loop is the issue.
for(y=0; y<num_jobs; y++)
{
printf("Program: %s", names[y]);
printf("\n memory size is as follows: ");
printf("\n memory start: %d memory end: %d", mem_st[y], mem_end[y]);
}
In C, the variables are given at the end of the printf. Also you are printing names two times, which i guess you don't want.