I'm starting to learn C and would like input characters from a command line and sort them into an array such that the row number is the ASCII character number and the columns are the index of the character from the input. I know that this must be dynamically done via realloc and malloc but I wouldn't know how to code it up. Could someone help me with this problem?
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#define totalASCII 256
int
main(int argc, char **argv) {
int locat;
char current;
int **dRow=NULL;
dRow = malloc(totalASCII*sizeof(*dRow));
for(locat=0;scanf("%c", ¤t)==1;locat++) {
/* I don't know what to put here */
}
return 1;
}
Your data is so small, there's really no need to allocate it from the heap. Just use an array:
struct { char character; int input_index; } input_data[totalASCII];
On a typical 32-bit system, this will use about 256 * 8 or 2 KB of memory, which really isn't all that much.
Then the storing would be:
for(locat = 0; scanf("%c", ¤t) == 1; locat++)
{
input_data[locat].character = current;
input_data[locat].input_index = locat;
}
Disclaimer: haven't compiled and run the code.
Try something like this:
int prev_size = 1;
dRow = calloc(totalASCII, sizeof(*dRow)); //use calloc
for(locat=0;scanf("%c", ¤t)==1;locat++) {
if(dRow[current]) {
prev_size=0;
//try to find how much is already allocated
while(dRow[current][prev_size] != -1)
prev_size++;
dRow[current] = realloc(sizeof(int) * (prev_size+1));
}
else {
prev_size = 1;
dRow[current] = malloc(sizeof(int) * (prev_size+1));
}
dRow[current][prev_size-1] = locat;
dRow[current][prev_size-1] = -1; //end identifier
}
The complexity here is to find the previous allocated size. As there is no other structure/data structure to store this info, this sample code tries to iterate over the array and find -1 which is assumed as end marker.
Related
Fairly new to C, I am trying to read a file of multiple words using bash indirection, and put the words into a string array. The end of the file is marked with a -1.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void init(char* words[]);
int main(int argc,char *argv[]){
char* words[400000];
init(words);
int i = 0;
do{
printf("%s",words[i]);
i++;
}while(!strcmp(words[i],"-1"));
}
void init(char* words[]){ // initializes array
int i = 0;
do{
fgets(words[i],1024,stdin);
i++;
}while(!strcmp(words[i],"-1"));
}
This gives me a segmentation fault, if any other information is needed I'm more than happy to provide it.
If I guessed correctly, '400000' means the max lines the user can input. But the default size of stack on Windows OS is 1M, sizeof(void*) * 400000 = 1,600,000...
The other thing is that you have not allocated memory for every line.
So, I try to correct your code like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE 4000 // '400000' is really too big!
void init(char* words[]);
int main(int argc,char *argv[]){
char* words[MAX_LINE];
memset(words, 0 , sizeof(words));
init(words);
int i = 0;
do{
printf("%s",words[i]);
delete words[i];
words[i] = nullptr;
i++;
}while(!strcmp(words[i],"-1"));
}
void init(char* words[]){ // initializes array
int maxLen = 1024;
int i = 0;
do{
words[i] = new char[maxLen];
memset(words[i], 0, maxLen);
fgets(words[i], maxLen, stdin);
i++;
}while(!strcmp(words[i],"-1") && i < MAX_LINE);
}
I am working on creating a shell and I haven't use C for a while. I have the shell initizing properly but when I try to compare the user input to an array of strings I have I get a segmentation fault. I was planning on adding casce statements in a the for loop to initiate each of the processes once they are called by the user. I haven't included those since I have been trying to figure out how to get the user input to match with a value in my string array. Under debug I was only receiving the first character of the builtins[j] value which kind of makes since since it is a pointer right. However I am stuck and could use some ideas for why this isn't returning 0 when I input "exit". Thanks
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
//This code is for creating a basic shell
void init_shell(int num, char *prompt[]){
char s1[] = "-p";
int result;
if(num>1){
result = strcmp(s1, prompt[1]);
if(result==0){
printf("%s>$", prompt[2]);
}else{
printf("308sh>$");
}
}
//printf("%s\n %s\n %s\n %d\n", prompt[0], prompt[1], prompt[2], result);
else{
printf("308sh>$");
}
}
//The infinite loop for accepting user input until it closes
int main(int argc, char *argv[]){
const char *builtins[7];
builtins[0] = "exit\n";
builtins[1] = "pid\n";
builtins[2] = "ppid\n";
builtins[3] = "cd\n";
builtins[4] = "pwd\n";
builtins[5] = "set\n";
builtins[6] = "get\n";
char usr_in[]="";
char cmp[]="";
while(1==1){
init_shell(argc, argv);//intial prompt for the shell
fgets(usr_in,100,stdin);
//Check for builtin Commands
int cmds_size = 7;
int j=0;
int res;
for(j; j<cmds_size; j++){
res=strcmp(usr_in, hold);
if(res==0){
printf("Execucting\n");
}
else{
printf("no command\n");
}
}
}
return(0);
}
The issue here is that you're writing the user's input to a buffer that isn't big enough to hold anything other than a null terminator.
char user_in[] = "";
The above line tells the C compiler that you need just enough space to store [ '\0' ], which is a single byte. The C compiler doesn't know that you may later write a 100-byte string to that buffer.
When you write to the buffer, the user's input overflows and will overwrite other values in your stack. Since the other values in your stack are pointers, what'll happen is you'll run into seg-faults, since you're writing character values into those bytes, but interpreting them as char pointers.
You are correctly limiting the size of the allowed input from the user to 100 characters, but you should make sure that your buffer is big enough to hold the value you're reading in:
char user_in[101];
for(int i = 0; i < sizeof(user_in) / sizeof(user_in[0]); i++) {
user_in[i] = 0; // Since this is allocated on the stack *in main*, this
// shouldn't be necessary
}
Here's one example of how you can rewrite your main method:
#include <stdio.h>
#include <string.h>
typedef enum { false, true } bool; // If you don't have this
// defined already
int main(int argc, char *argv[]) {
const char *builtins[7];
builtins[0] = "exit\n";
builtins[1] = "pid\n";
builtins[2] = "ppid\n";
builtins[3] = "cd\n";
builtins[4] = "pwd\n";
builtins[5] = "set\n";
builtins[6] = "get\n";
char user_in[101];
for(int i = 0; i < sizeof(user_in) / sizeof(user_in[0]); i++) {
user_in[i] = 0;
}
while(1) {
printf("Enter a command: ");
fgets(user_in, 100, stdin);
bool found = false;
for(int i = 0; i < sizeof(builtins) / sizeof(builtins[0]); i++) {
if (!strcmp(user_in, builtins[i])) {
printf("Found command %s", builtins[i]);
found = true;
break;
}
}
if (!found) {
printf("Didn't find command\n");
}
}
return 0;
}
Also, regarding your function init_shell: you're checking to see if argc is greater than 1, but that only guarantees that argv[1] is defined; it doesn't guarantee that argv[2] is defined. (Remember, argc is the size of the argv array, where the first element is the name of the program being executed). You want to make sure that argc is at least 3 before checking for the prompt flag in the way you are.
It may be overkill for your use-case, but consider using the getopt function for getting a custom prompt value from the user. See http://man7.org/linux/man-pages/man3/getopt.3.html for documentation regarding that method.
I want to initialize an array of size 1MB. So my goal is finally write that 1MB to a file.
I am curious every time i use this formula it is giving less than 1mb.
int len = (1048576)/sizeof(int);
data = (int *) malloc(len);
What is correct way ?
Thank you
Edit - As per the comments I have changed the code .
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <string.h>
int main(int argc, char *argv[]) {
int *data;
int bytes = (1024*1024);
data = (int *) malloc(bytes);
for(int i=0;i<bytes;i++){
data[i] = (int)rand();
printf("%d",data[i]);
}
return 0;
}
After compiling it and I tried dumping the data like below
mpicc -o a mpiFileSize.c
./a > dump.dat
Now I see the file size of dump.dat. Why its 2.5MB ?
Try this
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *data;
int bytes = (1024*1024);
data = (char *) malloc(bytes);
for(int i=0;i<bytes;i++){
data[i] = (char) rand();
printf("%c",data[i]);
}
return 0;
}
You shoul use character instead of integer.
Although it was already properly answered.
Just a plus to the answer, if one wants to choose the amount of MBs to allocate would make something like:
#include <malloc.h>
#define Mebabyte (1024 * 1024)
int main(int argc, char** argv)
{
void* data = malloc(2 * Megabyte);
// Do your work here...
free(data);
return 0;
}
If you wanted to allocate more than 2 MBs just change the 2.
As already stated before do not use integers as it's going to have more than 1 byte of size. Instead use char or unsigned char. And as stated by another post, there's no need to cast the result of malloc since void* can be turned to a pointer to any type (and in fact it's done implicitly by the compiler).
see: Why does this code segfault on 64-bit architecture but work fine on 32-bit?
/* This Program generates a file with a pseudo-random number of st_record_t structures. The file is passed by command line arguments. The program must by executed, in UNIX, this way: ./file_gen -path <path> */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "types.h"
#define MSG_INVALID_INPUT "Your input was not valid"
#define CMD_FLAG_PATH_POSITION 1
#define CMD_ARG_PATH_POSITION 2
#define CMD_FLAG_PATH "-path"
#define SDM_MAX 10000.0
status_t validate_arguments (int argc, char * argv []);
int main (int argc, char * argv [])
{
FILE * fi;
size_t i;
st_record_t aux_struct, aux2_struct;
int size;
if ((validate_arguments(argc, argv))!= OK)
{
fprintf(stderr, "%s\n", MSG_INVALID_INPUT);
return EXIT_FAILURE;
}
if((fi = fopen(argv[CMD_ARG_PATH_POSITION], "wb")) == NULL)
return EXIT_FAILURE;
srand(time(NULL));
for (i=0; i<(size=100); i++)
{
aux_struct.SDM = (((float)rand()/(float)(RAND_MAX)) * SDM_MAX); /*pseudo-random real number between 0 and SDM_MAX*/
(aux_struct.ID) = i;
(aux_struct.coordinates)->latitude.deg = rand()%180;
(aux_struct.coordinates)->latitude.min = rand()%60;
(aux_struct.coordinates)->latitude.sec = rand()%60;
(aux_struct.coordinates)->longitude.deg = rand()%180;
(aux_struct.coordinates)->longitude.min = rand()%60;
(aux_struct.coordinates)->longitude.sec = rand()%60;
if((fwrite (&aux_struct, sizeof(st_record_t), 1, fi))!=1)
return ERROR_WRITING_FILE;
}
if(fclose(fi) == EOF)
return EXIT_FAILURE
return EXIT_SUCCESS;
}
The problem is with the (aux_struct.coordinates)->latitude.deg = rand()%180 lines. If instead of using a random number I select one, this won't happen
The st_record_t struct is defined this way:
typedef struct {
unsigned char deg, min, sec;
}angle_t;
typedef struct {
angle_t latitude, longitude;
}st_coord_t;
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
The segmentation fault has nothing to do with random number, it's because you never allocate memory for aux_struct.coordinates.
To fix the problem, use something like:
aux_struct.coordinates = malloc(sizeof(st_coord_t));
Remember to free the memory when it's not used any more.
In addition to the issue of the missing initialization of the "coordinates" member, it should be pointed out that the fwrite() will not do what you want. It will just write the contents of the st_record_t. The value of the pointer "coordinates" has no meaning outside the process that is doing the writing and the data in the st_coord_t structure it points to will not get written at all.
You might want to look at something like hdf5 to write complex binary data structures to file in a portable way.
You have
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
As you can see,coordinates is a pointer of type st_coord_t. You need to allocate memory for it using malloc:
aux_struct.coordinates=malloc(sizeof(st_coord_t));
And you need to free the allocated memory after its use using:
free(aux_struct.coordinates);
Note that you must allocate memory for coordinates in aux2_struct if you want to use it and later free it after its use.
I'm getting this error on line #4 which says 'invalid initializer'. I know what the error means, but I can't work out why i'm getting the error. I've tried all sorts of combinations of pointers and values, but it doesn't seem to want to work. Any help / feedback for the code would be greatly appreciated.
Note: I plan to have a 2D array for the chessboard, which mean 64 ints of memory malloc'd.
The printf is there to keep the compiler happy and show me whether at [4][2] there is a '0'.
int *newBoard();
int main(int argc, char *argv[]) {
int *chessBoard[7][7] = *newBoard();
printf ("%d", chessBoard[4][2]);
return EXIT_SUCCESS;
}
int *newBoard() {
int counter = 0;
int *blankBoard = malloc(sizeof((int) * TOTALSPACES));
while (counter < TOTALSPACES) {
blankBoard[counter] = VACANT;
counter++;
}
return blankBoard;
}
newBoard returns an array of TOTALSPACES ints. int *chessBoard[7][7] = *newBoard(); LHS is a 7x7 array of int pointers (not ints). RHS is what, the contents of of an int pointer returned by the call? (what do you think the * infront of the call to newBoard() is doing?
Either int *newBoard = newBoard(); (to use heap memory) or int newBoard[7][7]; (to use stack memory) would work. You are trying to do half of each!
int *chessBoard[7][7] stands for an 2D array(7*7), each element type is int*;
but *newBoard() stand for an int element.
#include <stdio.h>
#include <stdlib.h>
#define TOTALSPACES 8*8
#define VACANT '0'
void *newBoard();
int main(int argc, char *argv[]) {
int (*chessBoard)[8][8] = newBoard();
printf ("%d", (*chessBoard)[4][2]);//48 : '0'
return EXIT_SUCCESS;
}
void *newBoard() {
int *blankBoard = malloc(sizeof(int) * TOTALSPACES);
int counter = 0;
while (counter < TOTALSPACES)
blankBoard[counter++] = VACANT;
return blankBoard;
}