fscanf crashing my C program, no idea why - c

EDIT: Question answered, I had a typo in my first for loop. Thanks so much everyone for catching that.
I'm working a C project for uni, and I'm having a problem I just cannot figure out. In one section of the program, I have to read in a few strings of symbols into a 2D character array in a struct (aka a "stamp"). Here is the code in my function:
stamp_t * read_stamp_type1(FILE * fptr)
{
//variable declaration
int r = 0, c = 0;
//creating a struct stamp_t and mallocing memory
stamp_t *newstamp1;
newstamp1 = malloc(sizeof(stamp_t));
//reading in values for the rows and columns of the "stamp" to be read in
fscanf(fptr, "%d %d\n", &r, &c);
//storing these values
newstamp1->num_rows = r;
newstamp1->num_cols = c;
//creating memory for newstamp1's grid
newstamp1->grid = malloc(sizeof(char *) * (r));
for(int i=0; i < c; i++)
newstamp1->grid[i] = malloc(sizeof(char) * (c+1));
//string to temporarily store input
char rowvalues[c+1];
//Note: Everything works up until this point
//the below lines crash the program every time
for(int i = 0; i < r; i++)
{
fscanf(fptr, "%s", rowvalues);
for (int j=0; j < c; j++)
strcpy(newstamp1->grid[i], rowvalues);
}
free(rowvalues);
return(newstamp1);
}
For some reason when I try to fscanf the string from the text file, it crashes the program (or at least that's what I think the cause is...).
For reference, here is the struct declaration:
// A structure for holding a stamp
typedef struct
{
// The size of the contents of this stamp.
int num_rows;
int num_cols;
// A 2D array of characters for a stamp.
char **grid;
} stamp_t;
And here is the input to the program:
3 4
.#.#
#.#.
.#.#
Any advice would be greatly appreciated, I can't seem to find any problem with the code. I have tried manually assigning values to each value in the rowvalues array, which works fine (rowvalues[0] = 'c'; works fine). I need to read in the 3 lines of symbols into newstamp1.grid, which is a 2D array. I ran a debugger and it said it's try to write to memory that is not allowed ("Access violation writing location"). I emailed my professor but he hasn't be in class for the past week and he isn't responding to email...
Thanks so much in advance.

For starters there is a typo in this loop
newstamp1->grid = malloc(sizeof(char *) * (r));
for(int i=0; i < c; i++)
^^^^^^
newstamp1->grid[i] = malloc(sizeof(char) * (c+1));
There must be
for(int i=0; i < r; i++)
^^^^^^
This loop
for (int j=0; j < c; j++)
strcpy(newstamp1->grid[i], rowvalues);
does not make sense. It seems you mean just
strcpy(newstamp1->grid[i], rowvalues);
Or maybe you have to allocate a 3D character array (that is a two dimensional array of strings) if each row in the file contains c strings.
And this statement
free(rowvalues);
is wrong. The variable rowvalues has automatic storage duration. So you may not call the function free for it.

This part of your code is nonsense:
newstamp1->grid = malloc(sizeof(char *) * (r));
for(int i=0; i < c; i++)
newstamp1->grid[i] = malloc(sizeof(char) * (c+1));
You allocate r items, and then your for is repeated as c-times. This should be the same, either both r, or both c. I bet i < r is correct condition there.
Also, as Vlad from Moscow pointed out, there is one more bug in the code: The final free shouldn't be there at all, because it wasn't mallocated. And the for-j line can also be omitted. (But it shouldn't produce any errors, it just unneededly repeats the same code.)

Related

Filling and Printing a 2D array

So I have a 2D array that I want to use later. Right now I just want to fill the empty spots.
So far I've just been messing around with array types and different default values. From my understanding a new array is filled with '0', I have tried NULL aswell.
int r = 5;
int c = 5;
int i;
int j;
int k = 0;
int area = r*c;
const char *array[r][c]; //tried char array[r][c] and other types
Setup my initial values and array here.
while(k< area){
for (j = 0; j < c; j++){
for (i = 0; i<r; i++){
if (array[i][j] == 0){
board[i][j] = ".";
}
printf("%c",aray[i][j]);
if (i = r - 1){
printf("\n");
}
k++;
}
}
}
This is where I try replacing all non filled values (all of them at this point) with ".", so the output should be a row of 5x5 dots. Instead I get weird letters and numbers. I have tried %s insead of %c, and no luck there but the output was different. Where I do %s I get some dots, but still not on a grid and the weird values show up.
Also Im pretty sure printf in a for loop, by default does it on a new line so I won't get the grid, so is there a better way of doing this?
What you have is an array of pointers. This would be suitable for a 2D array of strings, but not for a 2D array of characters. This isn't clear from your question, so I'll assume that you actually want a 2D array of characters. The syntax is: char array [r][c];.
Notably, since you used r and c which are run-time variables, this array is a variable-length array (VLA). Such an array cannot be placed at file scope ("global"). Place the array inside a function like main().
In order to use VLA you must also have a standard C compiler. C++ compilers and dinosaur compilers won't work.
Since you will have to declare the VLA inside a function, it gets "automatic storage duration". Meaning it is not initialized to zero automatically. You have to do this yourself, if needed: memset(array, 0, sizeof array);. But you probably want to initialize it to some specific character instead of 0.
Example:
#include <stdio.h>
#include <string.h>
int main (void)
{
int r = 5;
int c = 5;
char array [r][c];
memset(array, '#', sizeof array);
for(size_t i=0; i<r; i++)
{
for(size_t j=0; j<c; j++)
{
printf("%c", array[i][j]);
}
printf("\n");
}
}
Output:
#####
#####
#####
#####
#####
From my understanding a new array is filled with '0'
const char *array[r][c];
No*, you have fill it yourself in a double for loop, like this:
for(int i = 0; i < r; ++i)
for(int j = 0; j < c; ++j)
array[i][j] = 0
since your structure is a variable sized array.
Instead I get weird letters and numbers
This happens because your code invokes Undefined Behavior (UB).
In particular, your array is uninitialized, you then try to assign cells to the dot character, if their value is already 0.
Since the array is not initialized, its cells' values are junk, so none satisfied the condition of been equal to 0, thus none was assigned with the dot character.
You then print the array, which still contains garbage values (since it was never really initialized by you), and the output is garbage values.
* As stated by #hyde, this is true for local non-static arrays (which is most probably your case). Statics and globals are default initialized (to zero if that was the case here).
You have several problems:
You are declaring a pointer to the array you want, not the array
Whenever R and C are not compile time known, you can't use a built in array. You might can however use VLAs (C99 as only C standard has VLAs mandatory, C11 made them optional again), which seems like a built in array with a size not known at compile time, but has very important implications, see : https://stackoverflow.com/a/54163435/3537677
Your array is only zero filled, when declared as a static variable.
You seem to have mistake the assign = operator with the equal == operator
So by guessing what you want:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define R 5
#define C 5
int r = R;
int c = C;
int i;
int j;
int k = 0;
int area = R*C;
const char array[R][C];
int main() {
while(k< area){
for (j = 0; j < c; j++){
for (i = 0; i<r; i++){
if (array[i][j] == 0){
}
printf("%c",array[i][j]);
if (i == r - 1){
printf("\n");
}
k++;
}
}
}
//or
char** dynamic_array = malloc(r * c);
if (dynamic_array == NULL) {
perror("Malloc of dynamic array failed");
return EXIT_FAILURE;
}
memset(dynamic_array, '0', r*c);
k = 0;
while(k< area){
for (j = 0; j < c; j++){
for (i = 0; i<r; i++){
if (dynamic_array[i][j] == 0){
}
printf("%c",dynamic_array[i][j]);
if (i == r - 1){
printf("\n");
}
k++;
}
}
}
return 0;
}

Concatenating two 2d char arrays

I wrote a small program to combine two 2d arrays. Here is the code:
#define MAX 7
int main(void) {
int i, j;
char *array1[] = {"Welt,", "bist", "du"};
char *array2[] = {"noch", "zu", "retten?"};
char final[MAX][MAX];
for(i = 0; i < 3; i++) {
// initialize ith names element with first name
strcpy(final[i], array1[i]);
}
for(j = 0; j < 3; j++) {
// concatenate the last name to the firstname+space string
strcat(final[i], array2[j]);
}
for (i = 0; i != 6; i++) {
printf("%s", final[i]);
}
return EXIT_SUCCESS;
}
I get really strange output like:
Welt,bistbistdunochzuretten?uretten?en?
while what I want is this:
Welt,bistdunochzuretten
As you can see it is not completely wrong. There should not be a space between the words.
How can I fix my code?
The problems were that in the second for you were doing strcat(final[3], array2[j]);, because i was 3 at that point and in the final for you were trying to print from final[0] to final[5], when you only had defined final[0] to final[3] (where on final[0] to final[2] you had the names, and in final[3] you had all the last names concatenated which also exceeded the limit of characters), and without printing them in a new line it was hard to tell which string was what.
Try this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 7
int main(void) {
int i,j;
char *array1[] = {"Welt","bist","du"};
char *array2[] = {"noch","zu","retten?"};
char final[MAX][MAX];
for(i=0;i<3;i++)
strcpy(final[i], array1[i]); //To initialize ith names element with first name
for(j=0;j<3;j++)
strcat(final[j],array2[j]); //Concatanate the last name to the firstname+ space string
for (i = 0; i < 3; i++)
printf("%s\n", final[i]);
return EXIT_SUCCESS;
}
There are several problems with your code:
The constant MAX is not large enough for your data. The string "retten?" contains seven characters plus one terminating byte. As such, MAX must be at least 8, otherwise you get undefined behavior.
Your second loop contains uses the wrong index into final[i]. See point 3. for corrected versions.
The use of strcat() is wrong, you should be using strcpy() just like in the first loop. Together with point 2., your second loop should either look like this:
for(j = 0; j < 3; i++, j++) { //add increment for i
strcpy(final[i], array2[j]);
}
or like this:
for(j = 0; j < 3; j++) {
strcpy(final[3 + j], array2[j]); //derive the index from j
}
Regarding Point 1, I always advise against using any compile time constants like MAX. My experience is that these are just bugs that are waiting to strike. Someday, someone will have a use case that exceeds the limit, and your program goes boom. I always allocate buffers to fit the strings that I need to store, leaving the available RAM as the only limit to my code. To this end, functions like strdup() and asprintf() are extremely handy because they already do the allocation for me.
Regarding Point 2, you should try to declare all your loop variables right inside the initialization statement. Like so:
for(int i = 0; i < 3; i++) {
// initialize ith names element with first name
strcpy(final[i], array1[i]);
}
That way you don't run the danger of inadvertently using the loop variable after the loop / forgetting the initialization, etc. because your compiler will complain about the unknown variable.

Why do some C programs work in debug but not in release?

Ok,
So I am stuck here. I have code for a program that systematically executes people standing in a circle based off an algorithm, but I am having a problem with it crashing in release mode. My code runs fine if I run it using the debugger (codeblocks), but if I don't it crashes. I looked around online, and the only thing I am finding is unintialized variables, but I tried immediately setting values for my variables at declaration and it didn't fix the problem.
If anyone can see what my problem is, I would greatly appreciate help.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// if the program does not work, please run in debugger mode. It will work.
void remove_person(int** array, int arraySize, int position)
{
int i;
for (i = 0; i < arraySize; ++i)
printf("%d ", (*array)[i]);
printf("\n");
int* temp = malloc((arraySize - 1) * sizeof(int)); // create temporary array smaller by one element
memmove(temp,*array,(position+1)*sizeof(int)); // copy entire array before position
memmove(temp+position,(*array)+(position+1),(arraySize - position)*sizeof(int)); // copy entire array after postion
for (i = 0; i < arraySize - 1; ++i)
printf("%d ", (temp)[i]);
printf("\n");
free (*array);
*array = temp;
}
int kill(int** a, int n)
{
int pos = 0;
int round = 1;
while(n > 1)
{
pos = pos + 2 - (round % 2);
while(pos >= n)
pos = pos - n;
remove_person(a,n,pos);
n--;
while(pos >= n)
pos = pos - n;
round++;
}
return *a[0];
}
void main()
{
int n, survivor, i;
int* people;
printf("Enter number of people for Russian Roulette: \n");
scanf("%d", &n);
people = (int*) malloc(n*sizeof(int));
for(i=0; i < n; i++)
{
people[i] = i;
}
survivor = kill(&people, n);
printf("The survivor is person #%d\n", survivor);
}
The basic answer to the title question ("Why do some C programs work in debug but not in release?") is "when they invoke undefined behaviour".
Here, in
memmove(temp,*array,(position+1)*sizeof(int)); // copy entire array before position
memmove(temp+position,(*array)+(position+1),(arraySize - position)*sizeof(int)); // copy entire array after postion
you copy too much. To see why, observe that the first memmove copies to temp[0], temp[1], ..., temp[position], and the second copies to temp[position], temp[position+1], ..., temp[position+arraySize-position-1] = temp[arraySize-1] (note the overlap at temp[position]). But temp only has space for arraySize-1 elements -- you copied one more than it was allowed to hold, so you get undefined behaviour.
It probably works in debug but not release mode because the heap is laid out differently (debug-mode allocators may pad the allocations with extra space to catch bugs like this when running under a debugger or profiler).
The program segfaults if I enter 4 (or even numbers higher than 4) as input, but I won't go into the code to see why that happens.
Apart from that the program works just fine, the problem is that you don't see the output because I think you run it on windows.
That being said you should add something like scanf("%d", &n); at the end or run cmd.exe, go to the directory that holds the executable and run it from there.

What's wrong with my program?

I have written a program which could sort 5 strings you inputed from small to big. However, it can't work. I have worked at it for almost an hour, but I couldn't find out the problem. Here is the code.
#include <stdio.h>
#include <string.h>
main() {
char *sz[5], *temp;
int i, j;
for(i = 0; i < 5; i++) {
gets(sz[i]);
fflush(stdin);
}
for(i = 0; i < 5; i++) {
for(j = i+1; j < 5; j++) {
if(strcmp(sz[i], sz[j]) > 0) {
temp = sz[i];
sz[i] = sz[j];
sz[j] = temp;
}
}
puts(sz[i]);
puts("");
}
}
First huge problem is that you are using a routine that should never have existed, and using it improperly:
char *sz[5], *temp;
int i, j;
for(i = 0; i < 5; i++) {
gets(sz[i]);
You did not allocate any storage for gets() to store into, so it is simply scribbling on unrelated memory. (This often leads to security problems.)
You should pay special attention to the BUGS section in your manpages:
BUGS
Never use gets(). Because it is impossible to tell without
knowing the data in advance how many characters gets() will
read, and because gets() will continue to store characters
past the end of the buffer, it is extremely dangerous to use.
It has been used to break computer security. Use fgets()
instead.
Unlearn gets(3), now, and be a happier programmer.
Use malloc() to allocate some memory for those character arrays.
Ignacio hit another problem squarely on the head -- you're printing before your sort is finished. Add another loop to print, after the sorting. (Better yet, put the input, sort, and output into three separate functions. Perhaps you're not there yet, but it would be well worth doing this sooner rather than later, as it makes testing your programs significantly easier to have printing functions you can use for debugging.)
char *sz[5], *temp;
int i, j;
for(i = 0; i < 5; i++) {
gets(sz[i]); /* Tries to write data to random location. */
fflush(stdin);
}
At least 3 problems:
You're writing to uninitialized pointers. You need to initialize sz[i] before using it (perhaps using malloc)
fflush(stdin) is undefined behavior, drop it
gets is unsafe and was removed from the standard, drop it as well and use fgets instead
You are passing uninitialized pointers to gets, storing the data in random locations. This is undefined behavior. You should allocate memory for your data, and use fgets with limits to read strings.
char *sz[5], *temp;
int i, j;
char buf[100];
for(i = 0; i < 5; i++) {
fgets (buf , 100 , stdin);
sz[i] = strdup(buf);
}
... sort your strings...
// Free the strings before exiting the program
for (i = 0 ; i < 5 ; i++) free(sz[i]);

Deshuffle text with C

I wanted to get an opinion here. Would it be possible to write a C program that deshuffles a text file? What do I mean by that? Say I have the following data in a textfile:
1 X
4 T
3 Z
2 L
And I wanted to deshuffle it and output another file as so:
1 X
2 L
3 Z
4 T
Such that all of the data following the number is preserved with the actual index number. Do know that I have 40,500 shuffled entities, so that should probably be taken into account since that could take a long time if the program needs to loop through all of the entities for each entity...And I only used letters for representation. The actual data files don't have letters, but rather have floats. Sorry if this causes any confusion
So, bottom line, would this be possible with C? And if so, could I get a hint at where to start? I could obviously input all of the textfile data into an array dat[][], but how should I deshuffle it then?
Thanks!
Amit
Look up qsort, its part of stdlib.
I'd just use sort -n instead of writing a program.
If you know the largest index in the file and there are no holes (i.e. all indices are present), you can create an array of that size, then as you read each line of the file, put the data into the correct location in the array. When you're done reading the file, your array will have all the elements in the correct order.
You can build a vector< pair<int,float[4]> > and just sort it using STL.
Just noticed a c tag.... But C idea is about the same:
Build an array with the data:
struct pair
{
int idx;
float val[4];
}
pair *data;
And then just sort it.
For those interested, I ended up using a series of loops to write this program, the code is show below. The only downside of it is that if my nrow variable is equal to 40,500, this program can take as long as 30 mins to run on a 3GHz dual core computer. I'm sure there are ways to optimize it, though at least it does what I want...for now.
Here's the code:
#include "stdlib.h"
#include "stdio.h"
// Deshuffle the output files of the bond/swap mode
int main(int argc, char* argv[])
{
if (argc < 4) {
printf("\ndeshuffle usage: [number of chains] [number of atoms] [.dat file] \n");
exit(1);
}
int i,j,k,l;
int nch = atoi( argv[1] );
int ns = atoi( argv[2] );
double **in_dat, **s_dat, dm1;
int nrow = ns*nch;
in_dat = (double**) calloc(nrow, sizeof(double*));
s_dat = (double**) calloc(nrow, sizeof(double*));
for (i=0; i<nrow; i++) {
in_dat[i] = (double*) calloc(6, sizeof(double));
s_dat[i] = (double*) calloc(6, sizeof(double));
for (j=0; j<6; j++)
in_dat[i][j] = 0.0;
s_dat[i][j] = 0.0;
}
// store input data into 2D array in_dat
FILE *inp;
inp = fopen( argv[3], "r" );
for (i=0; i<nrow; i++) {
for (j=0; j<6; j++) {
fscanf(inp, "%lf", &dm1);
in_dat[i][j] = dm1;
}
}
fclose(inp);
// Sort data in s_dat based on comparison with in_dat
k=0;
while (k < (nrow)) {
for (i=0; i<nrow; i++) {
for (l=0; l<nrow; l++) {
if (in_dat[l][0] == (k+1)) {
for (j=0; j<6; j++) {
s_dat[i][j] = in_dat[l][j];
}
k++;
break;
}
}
}
}
// Write sorted data to file
FILE *otp;
otp = fopen("results.out", "w");
for (i=0; i<nrow; i++) {
for (j=0; j<6; j++) {
fprintf(otp, "%lf \t", s_dat[i][j]);
if (j==5)
fprintf(otp, "\n");
}
}
fclose(otp);
printf("\n Done. \n\n");
return 0;
}

Resources