Printing the contents of uneven (non-quadric) matrix in C - c

The goal of my assignment (ONLY C, NO C#,CPP ect...) was to get strings from the user, then trim the matrix to fit the exact data. This is my code:
void main(){
char** text=Q1();
int i;
printf("Lines entered:\n");
for(i=0;i<sizeof(text)/sizeof(char*);i++)
printf("%s\n",text[i]);
}
char** Q1(){
char OOM[]="Out of memory! exiting.";
char **buf=(char**)calloc(BUFFER,sizeof(char*)),**text;
int i,j;
if(buf==NULL){
printf(OOM);
exit(0);
}
for(i=0;i<BUFFER;i++){
buf[i]=(char*)calloc(BUFFER,sizeof(char));
if(buf[i]==NULL){
printf(OOM);
exit(0);
}
}
i=0;
do{
i++;
printf("Enter string #%d:\n",i);
gets(buf[i-1]);
}while(strlen(buf[i-1])>0 && i-1<BUFFER);
text=(char**)calloc(i,sizeof(char*));
if(text==NULL){
printf(OOM);
exit(0);
}
for(j=0;j<i;j++){
text[j]=(char*)calloc(strlen(buf[j]),sizeof(char));
if(text[j]==NULL){
printf(OOM);
exit(0);
}
strcpy(text[j],buf[j]);
}
free(buf);
return text;
}
Now I know this could be done with realloc (which I am not quite familiar with just yet).
I want to test that my allocations are okay and print the strings I saved in text.
What is the most intuitive way of doing that?
Thanks in advance!

First, this code:
for(i=0;i<sizeof(text)/sizeof(char*);i++)
printf("%s\n",text[i]);
Will not work.
sizeof(text) will return the size of a pointer since text is a char**. You'd want something like:
for (int i=0; i<BUFFER && text[i]!=0; i++)
printf("%s\n",text[i]);
But this requires that the last entry in text is a null pointer so you would need to allocate 1 more entry than required and set it to NULL.
Otherwise, you'll need to find some other way to return the size.
Next:
i=0;
do{
i++;
printf("Enter string #%d:\n",i);
gets(buf[i-1]);
}while(strlen(buf[i-1])>0 && i-1<BUFFER);
i will be 1 more than the number of entries. For example, if the user presses ENTER on the first try, i will be set to 1.
Why not?
for (i=0; i<BUFFER; i++) {
printf("Enter string #%d:\n",i+1);
gets(buf[i]);
if (strlen(buf[i])­==0) {
break;
}
}
This way i is set to the number of entries.
Assuming you make the change above then:
text=(char**)calloc(i,sizeof(char*));
Will need to be changed to:
text=(char**)calloc(i+1,sizeof(char*)); // Include an extra entry for the sentinel
text[i] = 0; // Add sentinel to indicate last entry
Also, when you allocate the space for the strings, you need to add 1 to the size to leave room for the terminating null character. So
text[j]=(char*)calloc(strlen(buf[j]),sizeof(char));
becomes
text[j]=(char*)calloc(strlen(buf[j])+1,sizeof(char));
And you forgot to free buf[0] to buf[BUFFER-1]
For the real question. I'm not sure what's expected your approach looks OK to me.

Related

How to handle buffer error while validating user input

I need to read in user input as an integer to pass it to my other function. If I use my validation (code below), it crashes after 4 bad inputs. I'm not completely sure if this is even a buffer error or not. But I also didn't find a proper way to validate my input and handle the errors. I didn't use scanf(%d) on purpose because I wanted to dodge the warning CLion is giving me when using it. I hope someone here can explain to me why my code is crashing after 4 bad inputs and how to fix it, or show me an alternative way.
char *userInput = malloc(100);
long amountOfPlayers;
//Todo: More Validation needed, bufferoverflow
for (int i = 0; i < sizeof(userInput) / sizeof(*userInput); i++) {
char *end;
printf("Please enter the amount of players: ");
scanf("%s", userInput);
amountOfPlayers = strtol(userInput, &end, 10);
if (end == userInput) {
printf("wasn't a number\n");
}
else if (end[0] != '\0') {
printf("trailing characters after number %ld: %s\n", amountOfPlayers, end);
}
else
return init_playerList(amountOfPlayers);
}
userInput is a pointer, not an array, so sizeof(userInput) returns the size of a pointer, typically 4 bytes. sizeof(*userInput) is sizeof(char), which is 1. So sizeof(userInput) / sizeof(*userInput) is 4, which means your for loop only executes 4 times. See How to find the 'sizeof' (a pointer pointing to an array)?
There's no need for a for loop, just use while (true). You're not doing anything that iterates over the elements of userInput, it's just the buffer.
There's also no reason to allocate it with malloc(), you can simply declare:
char userInput[100];
You have a memory leak because you never free(userInput) before returning from the function. But if you declare it as an array this is not necessary.
TO prevent buffer overflow you should use:
scanf("%100s", userInput);
sizeof(userInput) / sizeof(*userInput) won't return the number of elements, because userInput is a pointer, not an array. This only works for pure arrays. In case of pointer is always return the same value: size of a pointer divided by the size of the object.
int size = 100;
char *userInput = malloc(size);
if(userInput == NULL)
{
// error handling
}
for (int i = 0; i < n; i++) {
....
}
would be correct.

The Code exits after the input and output statements

After printing the 2nd printf the code exit and says Run Failed and says exit on level 2 ( whatever the input was )
void main()
{
int testcases;
int n_lines ,m_length;
int test, lines, length;
char n_m_matrix[n_lines][m_length];
printf("Enter the no. of Test Cases ");
scanf("%d",&testcases);
printf("%d",testcases);
for(test=0;test>testcases;test++)
{
printf("Enter the lines and length of the test cases ");
scanf("%d%d",&n_lines,&m_length);
for(lines=0;lines<n_lines;lines++)
{
for(length=0;length<m_length;length++)
{
scanf("%c",&n_m_matrix[lines][length]);
}
}
}
}
You need to move the declaration of n_m_matrix into the loop so that it's after you input the variables that hold the dimensions.
As others mentioned, you also have a typo in test > testcases, it should be <.
And you should read an extra character after entering the dimensions, to read the newline. Otherwise it will leave the newline after the dimensions in the input buffer, and this will be read as the first %c input when reading the contents.
You might also consider using fgets() to read each line, instead of doing it character by character. The way you've written it, if there are newlines at the end of each line, they will be inserted into the array. It's not clear whether that's wanted. If it is, make sure you include them in the line length input.
int main()
{
int testcases;
int n_lines ,m_length;
int test, lines, length;
printf("Enter the no. of Test Cases ");
scanf("%d",&testcases);
printf("%d\n",testcases);
for(test=0; test < testcases; test++)
{
printf("Enter the lines and length of the test cases ");
scanf("%d%d",&n_lines,&m_length);
getc(); // Skip over the newline
char n_m_matrix[n_lines][m_length];
for(lines=0;lines<n_lines;lines++)
{
for(length=0;length<m_length;length++)
{
scanf("%c",&n_m_matrix[lines][length]);
}
}
}
}
To clear confusion among the serveral problem the first one which invokes Undefined behavior in the code is, using uninitialized variable as VLA's size.
Also the for loop logic is wrong and character input might create some problem the way it is handled. (when entered with \n).
Correct code would be (considering that you don't want the whitespaces inputted into the array. Because if you do then there are other better choices like fgets etc).
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 1024
int main(void)
{
int testcases;
int n_lines ,m_length;
int test, lines, length;
printf("Enter the no. of Test Cases ");
if( scanf("%d",&testcases) != 1){
fprintf(stderr, "%s\n","Error in input" );
exit(1);
}
if( testcases <= 0 ){
fprintf(stderr,"%s\n","Enter nonzero integer for testcases");
exit(1);
}
printf("%d",testcases);
for(test = 0; test < testcases; test++)
{
printf("Enter the lines and length of the test cases ");
if(scanf("%d%d",&n_lines,&m_length)!=1){
fprintf(stderr, "%s\n","Error in input" );
exit(1);
}
if( n_lines <= 0 || m_length <= 0 || !(n_lines <= MAXSIZE && m_length <= MAXSIZE)){
fprintf(stderr, "%s\n","Error in input n_lines and m_length" );
exit(1);
}
char n_m_matrix[n_lines][m_length];
for(lines = 0; lines < n_lines; lines++)
{
for(length = 0; length < m_length; length++)
{
if( scanf(" %c",&n_m_matrix[lines][length]) != 1)
{
fprintf(stderr, "%s\n","Eror in input" );
exit(1);
}
}
}
// work with VLA here.
}
return 0;
}
Here if you need much larger array sizes than this go for dynamic memory allocation. That will satisfy larger memory requirement in array.
You need to use dynamic memory allocation, malloc method. The matrix n_m_matrix dimension is dynamically decided based on user input.
Allocate memory to n_m_matrix using malloc
In for loop correct logical error test>testcase to test<testcase
Put below code out of for loop
printf("Enter the lines and length of the test cases ");
scanf("%d%d",&n_lines,&m_length);

How to add string to array of strings in C

So I am getting re-acquainted with C, and this one concept has me particularly stuck.
The goal is to create a dynamically allocated array of strings. I have this done, first creating a null array and allocating the appropriate amount of space for each string entered. The only problem is, when I try to actually add a string, I get a seg fault! I can't figure out why, I have a hunch that it is from improper allocation as I can't see anything wrong with my strcpy function.
I have looked exhaustively on this site for an answer, and I have found help, but can't quite close the deal. Any help you can provide would be greatly appreciated!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int count = 0; //array index counter
char *word; //current word
char **array = NULL;
char *term = "q"; //termination character
char *prnt = "print";
while (strcmp(term, word) != 0)
{
printf("Enter a string. Enter q to end. Enter print to print array\n");
// fgets(word, sizeof(word), stdin); adds a newline character to the word. wont work in this case
scanf("%s", word);
//printf("word: %s\nterm: %s\n",word, term);
if (strcmp(term, word) == 0)
{
printf("Terminate\n");
}
else if (strcmp(prnt, word) == 0)
{
printf("Enumerate\n");
int i;
for (i=0; i<count; i++)
{
printf("Slot %d: %s\n",i, array[i]);
}
}
else
{
printf("String added to array\n");
count++;
array = (char**)realloc(array, (count+1)*sizeof(*array));
array[count-1] = (char*)malloc(sizeof(word));
strcpy(array[count-1], word);
}
}
return ;
}
word has no memory allocated to it. Your program in its current form is trampling over unallocated memory as users enter words into your program.
You should guesstimate how large your input would be and allocate the input buffer like this:
char word[80]; // for 80 char max input per entry

C - separating strings in the input stream

My program is supposed to be able to create new structures and store them in an array, however, the commands for storing and displaying pose difficulty.
To create a new variable struct in the array, the user inputs "set varname varcontents
To display the contents of a variable, the user inputs "set varname"
To display all variables, the user inputs "set"
I can't quite figure out how to check if there are multiple strings ("set" "varname" "varcontents") or if there is only "set"
char command[2][5] = { "set", "clear"};
printf("prompt> ");
scanf("%s",inputString);
if(strncmp(inputString,command[0],5) == 0 )
{
//code to create new struct, display structs etc...
}
else if(strncmp(inputString,command[1],5) == 0 )
{
//code to clear struct
}
Right now the if loop only passes if the user inputs "set".
I could probably take the comparison of the first few letters, and then take the full comparison and subtract the first few characters to generate the name of the new struct, but this seems too complicated, there must be an easier solution.
Any help is appreciated!
You could split the sentence into array of words and you can compare those words and run your functions.Give a try and If u want i can post the code.
There are some Problems in your code. First of all, scanf won't read "set variablename variablevalue", because it skips on whitespaces. It's not considered safe anyway, since it allows buffer overflows easily - specially beginners should rather use fgets().
But the main Problem is somewhere else - Consider the following snippet:
scanf("%s", inputString);
What would happen if you enter: 'set xyz 12'? scanf would just read 'set' and the other Input will be ignored. So there's no point in checking against the other parameters 'xyz' and '12'.
Maybe you want to use something like
scanf("%s %s %s", inputString1, inputString2, inputString3);
but I would advise against it and rather use fgets(). Apart from that you just Need simple pointer arithmetic to skip over the characters which you already processed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
char* command[] = { "set", "clear"};
char input[256], varName[256], varContents[256];
char* pointer = input;
int i = 0;
printf("prompt>");
fgets(input, 255, stdin);
if(strncmp(pointer, command[0], strlen(command[0])) == 0 ){
pointer += strlen(command[0]) + 1;
while(*pointer != ' ' && *pointer != '\n'){
varName[i] = *pointer;
pointer++;
i++;
}
if(*pointer == '\n'){ printf("Not enough arguments"); return 1; }
varName[i] = '\0';
pointer++;
i = 0;
while(*pointer != ' ' && *pointer != '\n'){
varContents[i] = *pointer;
pointer++;
i++;
}
varContents[i] = '\0';
//code to create new struct, display structs etc...
printf("Set VarName: %s VarContents: %s\n", varName, varContents);
}else if(strncmp(pointer, command[1], strlen(command[1])) == 0 ){
//code to clear struct
}
return 0;
}
You are only reading one string, you should use two scanf's to read two
char arg0[30], arg1[30];
while (scanf("%s %s", arg0, arg1) < 2);
That will read until both strings are entered.
Hope this helps.

realloc not working for 2-D pointer array

In the following code, I ask the user to give me some strings. I make a 2-D pointer char array, so that I read the input with pointer string which points to the start of a string of length 50. My problem is that I keep crashing after the input of the first string.. and I assume that my problem has to do with the realloc. I am not used to it.. can you please help to figure out what is happening?? I tried to debug with netbeans, but didn't manage to see anything interesting, since it doesn't give feedback for the new addresses made from realloc!!
Here is the code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *str,**string,buffer[50],temp[2];
int i,j,q,size,counter;
size=10;
string=(char**) calloc(size,sizeof(char*));
for (i=0; i<size; i++) string[i]=(char*) malloc(50*sizeof(char));
printf("\nGimme strings, terminate input with x");
i=0;
gets(string[i]);
temp[0]=120;//x
temp[1]='\0';
size=0;
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
return 0;
}
I want to make the table of pointers bigger with this realloc.
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
After you call realloc to enlarge string, the new portion contains no valid pointers. So when you call gets, you're passing it a pointer you failed to initialize.
Also, that size=0; is totally broken.
realloc does not initialize the allocated memory with zeros, in addition you forgot to initialize the newly allocated string pointers.
Consider to move up i++ and size++ within the while loop.
Code Review
initialize all your variables
char *str = NULL,**string = NULL,buffer[50] = {0},temp[2] = {0};
int i = 0,j = 0,q = 0,size = 10,counter = 0;
do not cast what is returned from malloc/calloc and use {} when possible for clarity
string=calloc(size,sizeof(char*));
for (i=0; i<size; i++)
{
string[i]=malloc(50*sizeof(char));
}
When reading from the keyboard do not use gets, use fgets() since you can specify the max size to read.
printf("\nGimme strings, terminate input with x");
char input[256];
fgets(input,sizeof(input),stdin); // another varname, will explain below
With newer compilers you can declare variables where you need them instead of decl at top of function.
char temp={'x','\0'}; // 120;//x
setting size=0 here seems a bit strange
size=0;
it is better to keep what the user inputs in a separate buffer (input)
then if it is not "x" copy it into your string array so instead of
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
e.g.
while (fgets(input,sizeof(input),stdin) != NULL && input[0] != 'x')
{
string[i] = calloc(1,strlen(input)+1); // add a byte for \0
strncpy(string[i],input,strlen(input)-1); // not copying ending \n
if ( ++i == size ) // a new chunk needed
{
char *newstring = realloc((size + 10)*sizeof(char*), string );
if ( newstring != NULL )
{
string = newstring;
size += 10;
}
}
}

Resources