I've been having a few problems with using an array of structs and simply listing them and adding to them. I am not really all too sure about what's happening, I've had a search around and asked a few friends and they've suggested that it is something to do with the memory allocation and another has said that memory allocation is not needed and that there is a problem in my code.
I have been unable to locate the problem and was wondering if anyone would be able to point me in the direction of to where I am going wrong.
I apologies if the code doesn't look right - not really sure on how to implement it on the site.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct data{
int testone;
int testtwo;
}data;
struct data _dataStore[25];
int dataCount = 0;
int addData(struct data __dataStore[dataCount]){
printf("\n\t\t\tPacket Source - ");
scanf("%i", &_dataStore[dataCount].testone);
printf("\t\t\tPacket Destination - ");
scanf("%i", &_dataStore[dataCount].testtwo);
system("CLS");
return 0;
}
void listData(struct data _dataStore[25]){
int i = 0;
for (i = 0; i < dataCount; i++){
printf("data stored - %i",dataCount);
printf("%i___%i \n", _dataStore[dataCount].testone,_dataStore[dataCount].testtwo);
}
}
int main(){
char choice;
do{
printf("\t\t\t Counter - %i", dataCount+1);
printf("\n\t\t\t1 - Add data. \n");
printf("\t\t\t2 - List data. \n");
printf("\n\t\t\tEnter your choice - ");
fflush(stdin);
choice = getchar();
getchar();
switch(choice){
case '1':
addData(&_dataStore[dataCount]);
dataCount++;
system("CLS");
break;
case '2':
system("CLS");
listData(&_dataStore[dataCount]);
break;
default:
printf("Invalid input \n");
break;
}
}while (choice != '5');
return 0;
}
There are quite a few apparent bugs, for example:
for (i = 0; i < dataCount; i++){
printf("data stored - %i",dataCount);
printf("%i___%i \n", _dataStore[dataCount].testone,_dataStore[dataCount].testtwo);
}
}
I suspect you wanted to say _dataStore[i] instead. Also, I suggest using a more sensible function prototype:
int addData(struct data* __dataStore, int arrayLen)
Here is the corrected code which works well for me:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct data{
int testone;
int testtwo;
}data;
struct data _dataStore[25];
int dataCount = 0;
int addData(){
printf("\n\t\t\tPacket Source - ");
scanf("%d", &_dataStore[dataCount].testone);
printf("\t\t\tPacket Destination - ");
scanf("%d", &_dataStore[dataCount].testtwo);
system("CLS");
return 0;
}
void listData(){
int i = 0;
for (i = 0; i < dataCount; i++){
printf("data stored - %d: ",dataCount);
printf("%d___%d \n", _dataStore[i].testone,_dataStore[i].testtwo);
}
}
int main()
{
char choice;
do{
printf("\t\t\t Counter - %i", dataCount+1);
printf("\n\t\t\t1 - Add data. \n");
printf("\t\t\t2 - List data. \n");
printf("\n\t\t\tEnter your choice - ");
fflush(stdin);
choice = getchar();
getchar();
switch(choice){
case '1':
addData();
dataCount++;
system("CLS");
break;
case '2':
system("CLS");
listData();
break;
case '5':
printf("Will exit...");
break;
default:
printf("Invalid input \n");
break;
}
}while (choice != '5');
return 0;
}
Please pay attention to the following: read / write integers with %d not %i, the index in listData() shall be i not dataCount, I removed the not-needed params of the functions since the variables are global, I added a new case in switch() so that it prints a better message when exiting, not "invalid input".
All variables you are using are statically allocated so you do not need memory allocation.
Related
Is there any way to hide user input when asked for in C?
For example:
char *str = malloc(sizeof(char *));
printf("Enter something: ");
scanf("%s", str);getchar();
printf("\nYou entered: %s", str);
// This program would show you what you were writing something as you wrote it.
// Is there any way to stop that?
Another thing, is how can you only allow certain characters?
For example:
char c;
printf("Yes or No? (y/n): ");
scanf("%c", &c);getchar();
printf("\nYou entered: %c", c);
// No matter what the user inputs, it will show up, can you restrict that only
// showing up if y or n are entered?
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
int set_disp_mode(int fd,int option)
{
int err;
struct termios term;
if(tcgetattr(fd,&term)==-1){
perror("Cannot get the attribution of the terminal");
return 1;
}
if(option)
term.c_lflag|=ECHOFLAGS;
else
term.c_lflag &=~ECHOFLAGS;
err=tcsetattr(fd,TCSAFLUSH,&term);
if(err==-1 && err==EINTR){
perror("Cannot set the attribution of the terminal");
return 1;
}
return 0;
}
int getpasswd(char* passwd, int size)
{
int c;
int n = 0;
printf("Please Input password:");
do{
c=getchar();
if (c != '\n'||c!='\r'){
passwd[n++] = c;
}
}while(c != '\n' && c !='\r' && n < (size - 1));
passwd[n] = '\0';
return n;
}
int main()
{
char *p,passwd[20],name[20];
printf("Please Input name:");
scanf("%s",name);
getchar();
set_disp_mode(STDIN_FILENO,0);
getpasswd(passwd, sizeof(passwd));
p=passwd;
while(*p!='\n')
p++;
*p='\0';
printf("\nYour name is: %s",name);
printf("\nYour passwd is: %s\n", passwd);
printf("Press any key continue ...\n");
set_disp_mode(STDIN_FILENO,1);
getchar();
return 0;
}
for linux
For the sake of completeness: There is no way to do this in C. (That is, standard, plain C without any platform-specific libraries or extensions.)
You did not state why you wanted to do this (or on what platform), so it's hard to make relevant suggestions. You could try a console UI library or a GUI library. You could also try your platform's console libraries. (Windows, Linux)
How to add if-else statement for "kodeprodi"?
Everytime I add if-else statement, the message "Lvalue required" always appears.
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef struct {
char bp[13];
char nama[15];
int kodeprodi;
char namaprodi[10];
float ipk;
} mahasiswa;
int main()
{
char pil;
do {
mahasiswa mhs[10];
int i, n;
{
printf("Data Nilai Mahasiswa\n");
printf("Berapa banyak data = ");
scanf("%d", &n);
for(i = 0; i < n; i++) {
printf("Data mahasiswa ke-%d\n", i+1);
printf("Nomor BP: "); scanf("%s", &mhs[i].bp);
printf("Nama: "); scanf("%s", &mhs[i].nama);
printf("Kode Prodi: "); scanf("%d", &mhs[i].kodeprodi);
printf("IPK: "); scanf("%f", &mhs[i].ipk);
if (mhs[i].kodeprodi == 260) {mhs[i].namaprodi = "SI";}
else if (mhs[i].kodeprodi == 261) {mhs[i].namaprodi = "TI";}
}
//output
printf("No. BP Nama Kode Prodi Nama Prodi IPK \n");
for(i = 0; i < n; i++) {
printf("\n%2d %-10s %-9s %3d %3s %3.f\n",
i+1, mhs[i].bp, mhs[i].nama, mhs[i].nama,
mhs[i].kodeprodi, mhs[i].namaprodi, mhs[i].ipk);
}
}
printf("Repeat again? Y/N");
scanf("%s", &pil);
printf("\n\n");
} while ((pil == 'Y') || (pil == 'y'));
}
Even if in the statement if-else, I type like this
if(mhs[i].kodeprodi==260){namaprodi = "SI");
The error message is "Undefined symbol 'namaprodi'
I tweaked your code a bit. Got rid of unused conio.h, changed kodeprodi type to int (because char can only handle numbers -127..127), removed & from some scanf calls (because you should pass pointer to first character for %s formatter), deleted extra mhs[i].nama argument for printf.
Sorry, I completely didn't understood your code :-) My tweaks were semi-automatic! You should learn C programming better.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char bp[13];
char nama[15];
int kodeprodi;
char namaprodi[10];
float ipk;
} mahasiswa;
int main() {
char pil;
do {
mahasiswa mhs[10];
int i, n;
{
printf("Data Nilai Mahasiswa\n");
printf("Berapa banyak data = ");
scanf("%d", &n);
for(i=0;i<n;i++) {
printf("Data mahasiswa ke-%d\n", i+1);
printf("Nomor BP: "); scanf("%s", mhs[i].bp);
printf("Nama: "); scanf("%s", mhs[i].nama);
printf("Kode Prodi: "); scanf("%d", &mhs[i].kodeprodi);
printf("IPK: "); scanf("%f", &mhs[i].ipk);
if(mhs[i].kodeprodi==260)
strcpy(mhs[i].namaprodi, "SI");
else if(mhs[i].kodeprodi==261)
strcpy(mhs[i].namaprodi, "TI");
}
//output
printf("No. BP Nama Kode Prodi Nama Prodi IPK \n");
for(i=0;i<n;i++) {
printf("\n%2d %-10s %-9s %3d %3s %3.f\n", i+1, mhs[i].bp, mhs[i].nama, mhs[i].kodeprodi, mhs[i].namaprodi, mhs[i].ipk);
}
}
printf("Repeat again? Y/N");
scanf("%s", &pil);
printf("\n\n");
} while ((pil == 'Y') || (pil == 'y'));
return 0;
}
For a quick fix, use:
if(mhs[i].kodeprodi==260){strncpy(mhs[i].namaprodi, "SI", 9);
strncpy() is needed to copy the contents into namaprodi.
namaprodi is a member of struct mahasiswa, so you can't access it directly.
But better use std::string instead.
Also, as #BoPersson mentioned, char kodeprodi; can't hold 260, so you'll better to convert that to an int.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
i want to make a x&0 game with ipc in c.i declare 3 char arrays,read the witch line to choose and the on what position to put the x or 0.when i try to send line number through the fifo from the client the server recieves a different number.for example i send 1 and the server gets 3144200....this is the code it's not all just one read and write.
this is the server:
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
int main() {
HANDLE f1, f2;
DWORD x;
char l1[3]="\0";
char l2[3]="\0";
char l3[3]="\0";
char X='x';
char* a="";
char* lineChar="";
int n=1,lineInt=0,coor=0;
printf("I am the server \n");
printf("You will play with x\n");
// creating pipes
f1=CreateNamedPipe(TEXT("\\\\.\\PIPE\\fifo1"), PIPE_ACCESS_INBOUND,PIPE_TYPE_BYTE|PIPE_WAIT, 3, 0, 0, 0, NULL);
f2=CreateNamedPipe(TEXT("\\\\.\\PIPE\\fifo2"), PIPE_ACCESS_OUTBOUND,PIPE_TYPE_BYTE|PIPE_WAIT, 3, 0, 0, 0, NULL);
ConnectNamedPipe(f1, NULL);
ConnectNamedPipe(f2, NULL);
while(n<=9){
for(int i=0;i<=2;i++){
printf("[%s]",&l1[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l2[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l3[i]);
}
printf("\n");
printf("You will begin,select the line from 1 to 3 : \n");
scanf_s("%d",&lineInt);
x=0;
lineChar=reinterpret_cast<char*>(lineInt);
printf("%s",lineChar);
//strcpy_s(a,sizeof(lineChar),lineChar);
if (WriteFile(f2,lineChar,sizeof(lineChar)+1, &x, NULL)==0) {
printf("writing error..%d\n", x);
}
n++;
}
DisconnectNamedPipe(f1);
DisconnectNamedPipe(f2);
CloseHandle(f1);
CloseHandle(f2);
}
this is the client :
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
int main(){
HANDLE f1, f2;
DWORD x;
char l1[3]="\0";
char l2[3]="\0";
char l3[3]="\0";
char o='0';
char* lineChar="";
int n=1,lineInt=0,coor=0;
printf("I am the client \n");
printf("You will play with 0\n");
// connect to pipes created by server
f1=CreateFile(TEXT("\\\\.\\PIPE\\fifo1"), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
f2=CreateFile(TEXT("\\\\.\\PIPE\\fifo2"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
while(n<=9){
for(int i=0;i<=2;i++){
printf("[%s]",&l1[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l2[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l3[i]);
}
printf("\n");
x=0;
Sleep(3000);
if (ReadFile(f2, lineChar, sizeof(lineChar), &x, NULL)==0) {
printf("reading error..%d\n", x);
}
printf("%s",lineChar);
//lineInt=atoi(lineChar);
//printf("\n%d\n",lineInt);
n++;
}
CloseHandle(f1);
CloseHandle(f2);
}
You have lots or problems with strings and pointers in your code.
To start with you print out the single characters in the arrays as strings, which will cause weird output.
Secondly, and one of the causes of your problem, when you call WriteFile you use sizeof(lineChar) which returns the size of the pointer, not the length of the string. Use strlen instead.
The second cause of your problem is that you cast an integer to a string. This will not work! What the statement
lineChar=reinterpret_cast<char*>(lineInt);
does is that it makes a pointer out of the value in lineInt. This is not a valid pointer! There are a couple of ways to do it:
Use the new std::to_string to convert a value to a std::string.
Since you mix C and C++ anyway, you could use sprintf too.
Your programs have a lot of what is called undefined behavior, and you should be happy that neither of them crashes outright.
#include<stdio.h>
#include<string.h>
int main(){
char l1[3]="\0";
char l2[3]="\0";
char l3[3]="\0";
char x='x';
char o='0';
int n=1,lineInt=0,coor=0,next=1;
printf("X & 0 Game : \n");
while(n<=3){
for(int i=0;i<=2;i++){
printf("[%s]",&l1[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l2[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l3[i]);
}
printf("\n");
switch (next){
case 1 :{
printf("To select the line enter 1,2 or 3 : \n");
scanf_s("%d",&lineInt);
switch (lineInt){
case 1 :{
printf("Enter the coordinates : \n");
scanf_s("%d",&coor);
//printf("%c",x);
//printf("%d",coor);
//strcpy_s(&l1[coor],1,"x");
l1[coor]=x;
break;
}
case 2 :{
printf("Enter the coordinates : \n");
scanf_s("%d",&coor);
l2[coor]=x;
break;
}
case 3 :{
printf("Enter the coordinates : \n");
scanf_s("%d",&coor);
l2[coor]=x;
break;
}
next=2;
}
for(int i=0;i<=2;i++){
printf("[%s]",&l1[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l2[i]);
}
printf("\n");
for(int i=0;i<=2;i++){
printf("[%s]",&l3[i]);
}
printf("\n");
case 2 :{
printf("To select the line enter 1,2 or 3 : \n");
scanf_s("%d",&lineInt);
switch (lineInt){
case 1 :{
printf("Enter the coordinates : \n");
scanf_s("%d",&coor);
l1[coor]=o;
break;
}
case 2 :{
printf("Enter the coordinates : \n");
scanf_s("%d",&coor);
l2[coor]=o;
break;
}
case 3 :{
printf("Enter the coordinates : \n");
scanf_s("%d",&coor);
l2[coor]=o;
break;
}
next=2;
}
}
}
n++;
}
}
}
I working my way through a C++ and Operating Systems book and I've come upon an assignment that requires creation, writing, and reading from pipes. However my program stalls on reading from the second pipe. My program is to accept input and parse out a space delimited string into tokens and classifying those tokens accordingly. My code is bellow with my problem area marked. Any help is as always very appreciated.
edit: This is supposed to have two children. One for processing the space delimited tokens and the other for determining the type of delimited tokens. As far as debugging goes I only have access to cout as a debugger. So I inserted a cout before the read and after the one before the read appeared but the one after did not.
#include <iostream>
#include <fstream>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
//declaring the pipes
int pipeOne[2];
int pipeTwo[2];
struct inputStruct {
char str[256]; /* one extra spot for \n */
int len; /* length of str */
int flag; /* 0 for normal input, 1 to indicate “done” */
};
struct tokenStruct {
char token[256]; /* tokens can be 255 max */
int flag; /* same as inputStruct */
int tokenType; /* a code value */
};
void dataProcess(){
//new input struct to contain the the input from the parent
inputStruct input;
//the intial read from the pipe to populate the input stuct
read( pipeOne[0], (char*)&input, sizeof(inputStruct));
//set the flag
int flag = input.flag;
while (flag != 1){
int size = 0;
//get the size of the array up until the null character
while (input.str[size] != '\0'){
size++;
}
//Here's the parsing of each token
for (int i=0; i<size; i++) {
int tokenLength;
tokenStruct token;
//while the char isn't white space or null increment through it
while (input.str[i] != ' ' && input.str[i] != '\0') {
//a is the index of the string token
int a = 0;
//write the parsed string
token.token[a] = input.str[i];
a++;
i++;
}
//write to process 2
write(pipeTwo[1], (char*)&token, sizeof(tokenStruct));
}
//read again and store the results
read(pipeOne[0], (char*)&input, sizeof(inputStruct));
flag = input.flag;
}
tokenStruct token;
token.flag = flag;
//final write to the second child to tell it to commit suicide
write(pipeTwo[1], (char*)&token, sizeof(tokenStruct));
exit(0);
}
void tokenClassifer(){
tokenStruct token;
//Problem area is here on ****************************************************
//the initial read
read(pipeTwo[0], (char*)&token, sizeof(tokenStruct));
while (token.flag != 1){
int size = 0;
//get the size of the array up until the null character
while (token.token[size] != '\0'){
size++;
}
if (size == 1) {
//check for the one char things first
switch (token.token[0])
{
case '(':
token.tokenType = 0;
break;
case ')':
token.tokenType = 0;
break;
case ';':
token.tokenType = 0;
break;
case '+':
token.tokenType = 1;
break;
case '-':
token.tokenType = 1;
break;
case '/':
token.tokenType = 1;
break;
case '*':
token.tokenType = 1;
break;
default:
if (isdigit(token.token[0])) {
token.tokenType = 2;
} else {
token.tokenType = 3;
}
break;
}
} else {
bool isStr;
int i = 0;
//check for the more than one character
while (token.token[i] != '\0'){
//check if it's a string or digits
if (isdigit(token.token[0])) {
isStr=false;
} else{
//set up the bools to show it is a string
isStr=true;
break;
}
}
//if it is a string token type 3
if (isStr) {
token.tokenType = 3;
} else {
//if not then it's digits and token type 2
token.tokenType = 2;
}
}
//print out the token and token type
cout << "Token type is: " << token.tokenType << "Token value is: " << token.token << "\n";
//read the pipe again and start the process all over
read(pipeTwo[0], (char*)&token, sizeof(tokenStruct));
}
exit(0);
}
int main()
{
//create the pipes for reading and writing between processes
pipe(pipeOne);
pipe(pipeTwo);
//fork off both processes
int value = fork();
int value2 = fork();
//do the process for the first fork
if(value == 0){
//fork one
dataProcess();
} else {
wait(0);
}
//do the process for the second fork
if (value2 == 0) {
//fork two
//the token classifer function for the second fork
tokenClassifer();
} else {
cout << "Type some tokens (or just press enter to quit) \n";
//this is all of the parent functions
for (string line; getline(cin, line); )
{
inputStruct input;
if (line.empty())
{
// if the line is empty, that means the user didn't
// press anything before hitting the enter key
input.flag = 1;
write( pipeOne[1], (char*)&input, sizeof(inputStruct));
break;
} else {
//else copy the string into an array
strcpy(input.str, line.c_str());
//set the flag to zero to show everthing is ok
input.flag = 0;
}
//write the stuct to the pipe
write( pipeOne[1], (char*)&input, sizeof(inputStruct));
cout << "Type some tokens (or just press enter to quit) \n";
}
wait(0);
}
}
One problem that is evident:
//fork off both processes
int value = fork();
int value2 = fork();
This will fork 3 new processes. The initial fork will leave you with two processes, each of which go on to fork a new process.
EDIT:
Proper forking:
int value = fork();
if (value == 0) {
// do child stuff
exit(0);
} else if (value == -1) {
//fork failed
}
int value2 = fork();
if (value2 == 0) {
//do child stuff
exit(0);
} else if (value2 == -1) {
//fork failed
}
I'm actually not quite clear about how data goes through your program, so I'll leave it to you to add the waits. I'd actually change the names of value and value2, but that's just me. Also, I'm only addressing the forking issue here so there may be other problems with your code (which I kind of suspect since you have two pipes).
EDIT 2:
Another issue that I see is that you're not closing the ends of the pipes that you don't use. If you never close the write end of a pipe, your reads will block until the pipe has data (or there are no more writers to the pipe, that is, the write end is not open). This means that the write end of the pipe should be closed in all processes when you are not using it or are finished with it.
I want to print an array of characters, these characters are underscores first.
Then the user can write characters on these underscores.I used gotoxy() but it doesn't work properly.
That is what i wrote:
int main(void)
{
char arr[20];
int i;
char ch;
clrscr();
for(i=0;i<=20;i++)
{
textattr(0x07);
cprintf("_");
}
do
{
for(i=0;i<=20;i++)
{
//gotoxy(i,0);
//ch = getche();
if( isprint(ch) == 1)
{
arr[i] = ch;
gotoxy(i,0);
//printf("%c",ch);
}
}
} while(i == 20);
getch();
return 0;
}
The first thing is this: You probably don't want to have all those calls to gotoxy, textattr and cprintf in your main function, since that is not what the main function is supposed to do.
It is much more likely that the main function's purpose is "to read some text from the user, presented nicely in an input field". So you should make this a function:
static int
nice_input_field(char *buf, size_t bufsize, int x, int y) {
int i, ch;
gotoxy(x, y);
for (i = 0; i < bufsize - 1; i++) {
cprintf("_");
}
i = 0;
gotoxy(x, y);
while ((ch = readkey()) != EOF) {
switch (ch) {
case '...': /* ... */
break;
case '\b': /* backspace */
cprintf("_");
i--;
gotoxy(x + i, y);
break;
case '\t': /* tabulator */
case '\n': /* enter, return */
buf[i] = '\0';
return 0; /* ok */
default: /* some hopefully printable character */
if (i == bufsize - 1) {
cprintf("\a"); /* beep */
} else {
buf[i++] = ch;
gotoxy(x + i, y);
cprintf("%c", buf[i]);
}
}
}
/* TODO: null-terminate the buffer */
return 0;
}
Printing an array of characters is fairly easy:
char* str = your_array;
while(*str) {
putc(*str++);
}
From memory that should print a string out to the screen.
Your code is very DOS-specific. There is not a good general solution to the problem of reading immediate input in a portable way. It does get asked quite often, so I think the C FAQ broke down and included an answer which you might want to seek out.
That said, I think your bug is that gotoxy(1, 1) is the upper corner of the screen, not 0,0. So you want gotoxy(i, 1)