I'm trying to write the values from the string that is read from stdin directly into the array, but I get a segmentation fault. Being that the array is declared after I read N and M, the memory should already be allocated, right?
int main()
{
long long N;
long long M;
scanf("%lld%lld",&N,&M);
char line[M];
long long map[N][M];
for (long long i=0; i<M; i++)
{
scanf("%s", &line);
buildMap(&map, i, &line);
}
for (long long i=0; i<N; i++)
for (long long j=0; j<M; j++)
printf(&map);
}
void buildMap(long long **map, long long i, char * line)
{
for (long long j=0; j<strlen(line); j++)
{
map[i][j] = line[j]-'0';
}
I have read your codes, and I assume you are attempting to build a 2D map via user input, which is a string (named "Line" in your code) that should only contains numbers from 0 to 9. Numbers from 0 to 9 may represent different elements of the map. Am I guessing right?
I copied and modified your code, and finally I managed to get a result like this:
program screenshot
If I am guessing right, let me first explain the reasons why your code can not be successfully complied.
long long M; char line[M];
In here you have used a variable to declare the size of an array. This syntax works in some other programming languages, but not in C. In C, when compling the source code, the compiler must know exactly how much stack memory space to allocate for each function (main() function in your case). Since the complier does not know how large the array is when it is trying to complie your code, you get a compling failure.
One common solution is that, instead of storing array in stack, we choose to store array in heap, because the heap memory is dynamically allocated and released when the program is running. In other words, you can decide how much memory to allocate after you get the user input. Function malloc() and free() are used for this kind of operation.
Another problem is using "long long **map". Though it will not cause complie failure, it won't give you the expected result either. When the M (array width) of the array is a known constant value, we always perfer using "long long map[][M]" as the parameter. However, in your case, with M being unkown, the common solution is to manually calculate the target location, since the elements in an array are always stored in a linear order in memory, regardless of the array demension.
I have fixed the aforementioned two problems, and I am pasting the modified source code below, which has been successfully complied:
#include <malloc.h>
#include <string.h>
void buildMap(int *map, int i, char * line);
int main()
{
int N;
int M;
scanf("%d%d", &N, &M);
/*Since M (available memory space for "Line") is set by user, we need to build
"szSafeFormat" to restrict the user's input when typing the "Line". Assuming M
is set to 8, then "szSafeFormat" will look like "%7s". With the help of
"szSafeFormat", the scanf function will be scanf("%7s", Line), ignoring
characters after offset 7.*/
char szSafeFormat[256] = { 0 };
sprintf(szSafeFormat, "%%%ds", M - 1);
//char line[M];
char *Line = (char *)malloc(sizeof(char) * M); //raw user input
char *pszValidInput = (char *)malloc(sizeof(char) * M); //pure numbers
//long long map[N][M];
int *pnMap = (int *)malloc(sizeof(int) * M * N);
memset(pnMap, 0xFF, M * N * sizeof(int)); //initialize the Map with 0xFF
for (int i = 0; i < /*M*/N; i++)
{
scanf(szSafeFormat, Line); //get raw user input
sscanf(Line, "%[0-9]", pszValidInput); //only accept the numbers
while (getchar() != '\n'); //empty the stdin buffer
buildMap((int *)(pnMap + i * M), i, pszValidInput);
}
printf("\r\n\r\n");
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
//if the memory content is not 0xFF (means it's a valid value), then print
if (*(pnMap + i * M + j) != 0xFFFFFFFF)
{
printf("%d", *(pnMap + i * M + j));
}
}
printf("\r\n");
}
free(Line);
free(pszValidInput);
free(pnMap);
return 0;
}
void buildMap(int *map, int i, char * line)
{
for (int j = 0; j < strlen(line); j++)
{
(int) *((int *)map + j) = line[j] - '0';
}
}
I used type "int" instead of "long long", but there should not be any problems if you insist to continue using "long long". If you continue to use "long long", the condition while printing out the array values should be changed from:
if (*(pnMap + i * M + j) != 0xFFFFFFFF)
to
if (*(pnMap + i * M + j) != 0xFFFFFFFFFFFFFFFF)
There are also some other modifications regarding user input validation, with which I have written some addtional comments in the code.
Remember that C supports variable-length arrays (something which you already use). That means you can actually pass the dimensions as arguments to the function and use them in the declaration of the array argument. Perhaps something like
void buildMap(const size_t N, const size_t M, long long map[N][M], long long i, char * line) { ... }
Call like
buildMap(N, M, map, i, line);
Note that I have changed the type of N and M to size_t, which is the correct type to use for variable-length array dimensions. You should update the variable-declarations accordingly as well as use "%zu for the scanf format string.
Note that in the call to buildMap I don't use the address-of operator for the arrays. That's because arrays naturally decays to pointers to their first element. Passing e.g. &line is semantically incorrect as it would pass something of type char (*)[M] to the function, not a char *.
Related
I was trying to convert a list of integers into a compact string but I get a segmentation fault.
The code is the following:
int *factors = job_factorization(number, size);
char buffer[250] = { 0 };
for (int i = 0; i < *size; i++) {
sprintf( &buffer[i], "%d ", *factors);
factors++;
}
The job_factorization function returns the head of the list (it works, I have already tested it), and it sets the value pointed to by size to the actual size of the list (so the number of integers).
I cannot figure out what is wrong, does anyone have any idea?
Note these remarks:
sprintf( &buffer[i], "%d ", *factors); does not convert the number at the end of the previous conversion.
sprintf does not check for buffer overflow: if size is large enough, it will eventually write beyond the end of the buffer.
modifying factors is probably not a good idea as this pointer should be freed after use.
Here is an alternative:
int *factors = job_factorization(number, size);
char buffer[1024];
size_t pos = 0;
for (int i = 0; pos < sizeof buffer && i < *size; i++) {
pos += snprintf(buffer + pos, sizeof buffer - pos, "%d ", factors[i]);
}
You could also use 2 loops to compute the size needed for the conversion and allocate the space needed.
I wrote the following function in C:
int last(long arr[], int length) {
for (int i = 0; i < length-1; i++)
if (*(arr+i) == *(arr + length - 1))
return 1;
return 0;
}
it checks if the last value of the array was used more than once. In the main:
int *arr = malloc(length*sizeof(int));
for (int i = 0; i < length; i++)
scanf("%d", ++arr);
printf(last((long *) arr, length);
For some reason for the array [1,2,2,3] it returns that the last element was used multiple times and I'm not sure why. I think that is because of scanf("%d", ++arr); but I don't know how to fix it.
My goal is that it will return 1 for [1,3,2,3] and 0 for [1,2,2,3]. What could be the problem?
You should use scanf("%d", &arr[i]);. Using ++arr causes the array to be incremented before you pass it to last, and also reads into data beyond arr, which is undefined behavior.
Another one of the issues in this is the cast to long *.
You should use %ld in scanf and long *arr = malloc(length*sizeof(*arr));.
Also make sure to check for NULL. You never know when malloc is going to fail or someone's going to pass bad data.
Full example:
#include <stdio.h>
#include <stdlib.h>
int last(long arr[], int length) {
if(!arr) return -1;
for (int i = 0; i < length-1; i++)
{
if (arr[i] == arr[length-1])
return 1;
}
return 0;
}
int main(void)
{
long *arr = malloc(4*sizeof(*arr));
if(!arr) return 1;
for (int i = 0; i < 4; i++)
scanf("%ld", &arr[i]);
printf("%d\n", last(arr, 4));
}
Several problems in your code:
Look at this statement:
scanf("%d", ++arr);
^^^^^
In the last iteration of loop, the pointer arr will be pointing to one element past end of array arr (due to pre-increment) and it is is passed to scanf(). The scanf() will access the memory location pointed by the pointer which is an invalid memory because your program does not own it. This is undefined behavior. Note that a pointer may point to one element past the end of array, this is as per standard but dereferencing such pointer will lead to undefined behavior.
Once the main() function for loop finishes the arr pointer pointing to location past the end of memory allocated to arr and just after this you are passing arr to last() function. So, you are passing an invalid memory reference to last() function and then accessing that memory in last() function - one more undefined behavior in your program.
Probably you should take another pointer and point it to arr, so that arr keep pointing to allcoated memory reference returned by malloc().
Note that if you want to read the input the way you are doing then use the post-increment operator in scanf(), like this:
int *arr = malloc(length*sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
int *ptr = arr;
for (int i = 0; i < length; i++)
scanf("%d", ptr++);
but the more appropriate and readable way is - scanf("%d", &arr[i]).
Another big problem in your code is accessing the int values as long type.
The last() function parameter arr type is long and you are passing it int pointer typecasted to long *.
Note that the size of long and int may be different based on the platform. You cannot assume them to be of same size on all platforms.
Assume the case where int size is 4 bytes and long size is 8 bytes.
In this case, when accessing an int pointer using long type pointer then every object will be considered as 8 byte long and when you do arr+1 in last(), the pointer will be advance by 8 bytes and you will never get correct result.
Compiler must be throwing warning message on this statement:
printf(last((long *) arr, length);
because the printf() expects first argument as const char * and you are passing it int (return type of last()). You should give the first argument to printf() a string which contains appropriate format specifier('s).
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
int last(int arr[], int length) {
if (arr == NULL) {
return 1;
}
for (int i = 0; i < length - 1; i++) {
if (arr[i] == arr[length - 1]) {
return 1;
}
}
return 0;
}
int main(void) {
int length = 4;
int *arr = malloc (length * sizeof (*arr));
if (arr == NULL) {
exit(EXIT_FAILURE);
}
printf ("Enter %d numbers:\n", length);
for (int i = 0; i < length; i++) {
scanf ("%d", &arr[i]);
}
printf ("Duplicate found: %s\n", last (arr, length) == 1 ? "Yes" : "No");
return 0;
}
I am trying to debug this code and I can't seem to find the error that is giving me this on the command line:
./thisa
thisa
isa
a
test
Instead, it needs to give me this:
./arguments
this
is
a
test
Assuming I enter "./arguments this is a test" as my input.
Any suggestions on where the bug might be?
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printArguments( int rows, int cols, char args[][ cols ] )
{
for (int i = 0; i < rows; i++) {
printf("%s\n", args[i]);
}
}
int main( int argc, char *argv[] )
{
// Figure out the length of the longest command-line argument.
int longest = 0;
for (int i = 0; i < argc; i++) {
int len = sizeof(argv[i])/sizeof(argv[0]);
if (len > longest) {
longest = len;
}
}
char (*words)[ longest + 1 ];
int n = argc;
words = (char (*)[longest + 1])malloc(n * (longest + 1) * sizeof(char));
// Copy each command-line argument to a row of this new array.
for (int i = 0; i < n; i++) {
strcpy(words[i], argv[i]);
}
// Call a function that's expecting the command-line arguments as a 2D array
printArguments( argc, longest + 1, words );
return 0;
}
There's quite a lot going on here. If you're simply trying to print the command-line arguments, you already have your answer in the guts of your helper function. Just use that code directly on argc/argv:
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
Since you go to all the trouble of copying everything out into an array with a completely different format, I'm assuming that there's more to this question than what you've given us so I'll address the question/code as written.
As several others have mentioned, the line len = sizeof(argv[i])/sizeof(argv[0]) will always return 1 since argv[x] is a pointer. To measure the length of argument number x, all you need is sizeof(argv[x]).
The line char (*words)[ longest + 1 ] declares a pointer to an array of (longest+1) characters. You then allocate a much larger buffer ((longest+1) * argc bytes) and assign it to the pointer. It's not clear what you're trying to do here. Generally speaking, when allocating a character buffer, you'd do something like this:
char* my_ptr;
my_ptr = malloc(num_bytes);
You don't need to encode anything about the size of a 1-D buffer in the pointer, a normal character pointer is all you need. You also don't need to typecast the return value of malloc(). It returns a void*, which will implicitly convert to any other pointer type without a cast.
The next piece of code is likely where you're encountering a lot of your problems.
for (int i = 0; i < n; i++) {
strcpy(words[i], argv[i]);
}
Here, words is a pointer to a 1-dimensional array. This code starts by copying argument #0 to byte 0 of the destination (OK). The next time through the loop, it copies argument #1 to byte 1 of the destination. This is going to overwrite part of your first argument. You have room in this buffer to write all of the arguments without overlapping, but your pointer is only a 1-D pointer (you're treating it like a 2-D pointer). To treat the destination like a 2-D matrix, you'll need to do some of the pointer arithmetic yourself:
strcpy(words[i * (longest + 1)], argv[i]);
That will write the first argument at byte 0, the second at byte (longest+1), the third at byte 2*(longest+1), etc., ensuring that they won't overlap. You'll need to make a similar change to your helper function as well.
I'm tasked with writing a function that will identify all the even numbers in an sample array {10,2,9,3,1,98,8] and place them in an array called EvenNumbers. I have to allow the function so that it works with different combinations of numbers in the array not just the numbers in the sample array above.
I'm wondering is there any way to add numbers to an array that could be different every time? How would I extract the even numbers an place them into an array? Also
for the even array size its giving me an error that the expression must have a constant value but when I use const int it still gives me that error.
Here is the full question.
"Using the array of sample values {10,2,9,3,1,98,8}, write a function that will identify all the even numbers in an array and place it in an array called EvenNumbers. The function must work in all cases, not just in the case of the array shown. Assume that the array size is always available through a global constant called MAX"
Here is what I have so far. I've no idea how I will extract the even numbers from a for loop and place them in an array. I also dont know what the "expression must have a constant value" is about?
#include <stdio.h>
#include <stdlib.h>
void EvenNumber(int Array[], int size);
int main()
{
int array[7] = { 10,2,9,3,1,98,8 };
EvenNumber(array, 7);
}
void EvenNumber(int Array[], int size)
{
int i;
int EvenArraySize;
for (i = 0; i < size; i++)
{
if (Array[i] % 2 == 0)
{
EvenArraySize++;
}
}
int Even[EvenArraySize];
}
The right way to go is to use malloc to allocate just the right amount of memory.
Count the number of even numbers
Allocate the space needed to store them
Copy even numbers in this space
Do whatever you want with these numbers
Free the allocated space
Snippet:
#include <stdio.h>
#include <stdlib.h>
#define MAX 7
int
main()
{
int array[] = {10,2,9,3,1,98,8};
int *even_numbers;
int i, nb_even_numbers;
for (i = 0, nb_even_numbers = 0; i < MAX; i++)
{
if (array[i] % 2 == 0)
nb_even_numbers++;
}
even_numbers = malloc(sizeof(int) * nb_even_numbers);
if (!even_numbers)
{
perror("malloc");
return 1;
}
for (i = 0, nb_even_numbers = 0; i < MAX; i++)
{
if (array[i] % 2 == 0)
even_numbers[nb_even_numbers++] = array[i];
}
/* do your stuff here */
free(even_numbers);
return 0;
}
First, you can never return a statically declared array from a function (even though you don't explicitly try, your Even array is destroyed when EvenNumber returns) Why? The function stack frame for EvenNumber is released for reuse on return and any locally declared arrays are no longer valid.
You either need to pass a second array as a parameter to EvenNumber, or you can dynamically allocate storage for Even in EvenNumber (with, e.g. malloc or calloc or realloc) and return a pointer to the beginning of the array. (you must also have some way to return the size or use a constant for a max size).
There is no need to use % (modulo) to test whether a number is odd/even. All you need to do is look at bit-0 (little endian). If it is 0, then the number is odd, if it is 1, then its even. Much more efficient than calling modulo which incorporates division.
Finally, main is type int and therefore returns a value.
Putting those pieces together, you can do something simple like the following:
#include <stdio.h>
#include <stdlib.h>
void EvenNumber (int *array, int *even, int size, int *esize);
int main (void)
{
int array[] = { 10,2,9,3,1,98,8 },
i, n = sizeof array / sizeof *array,
even[n], /* a VLA of the same size as array is fine here */
esize = 0;
EvenNumber (array, even, n, &esize);
printf ("array: ");
for (i = 0; i < n; i++)
printf (" %2d", array[i]);
printf ("\neven : ");
for (i = 0; i < esize; i++)
printf (" %2d", even[i]);
putchar ('\n');
return 0;
}
void EvenNumber (int *array, int *even, int size, int *esize)
{
int i;
for (i = 0; i < size; i++)
if ((array[i] & 1) == 0) /* simply looking at bit-0 is all you need */
even[(*esize)++] = array[i];
}
Note: esize is passed as a pointer to EvenNumber and updated within the function so that the number of elements in even are available back in the calling function (main() here).
Example Use/Output
$ ./bin/arrayeven
array: 10 2 9 3 1 98 8
even : 10 2 98 8
Let me know if you have any further questions.
I need to create a program that plays the game Hex on a 14x14 board.
So I created, allocated and filled the board with '-' (our pattern for empty spaces).
When I try to print the board's coordinates, I don't always get '-' but some random characters.
Also, if I try to printf array[i][j] on the createBoard function after the line "board[i][j] = '-';" I get a segmentation fault right after it prints tab[8][0].
What is causing this and how can I fix it?
My code:
#include <stdio.h>
#include <stdlib.h>
char **createBoard()
{
/*Allocates a 14x14 matrix and fills it
*with '-' to create the board.*/
int i, j;
char **board;
board = malloc(14);
if (!board) exit(1);
for (i = 0; i < 14; i++){
board[i] = malloc(14);
if (!board[i]) exit (1);
for (j = 0; j < 14; j++)
board[i][j] = '-';
}
return board;
}
int main()
{
int i, j;
char **board = createBoard();
for (i = 0; i < 14; i++)
for (j = 0; j < 14; j++)
printf("tab[%d][%d]: %c\n",i, j, board[i][j]);
return 0;
}
For starters it is not clear why you don't want to declare an array instead of allocating dynamically numerous one-dimensional arrays.
As for the code then this memory allocation
board = malloc(14);
is invalid. You have to write
board = malloc( 14 * sizeof( char * ));
Also you should free all the allocated memory in the reverse order relative to its allocation before the program ends.
Take into account that it is always better to use named constants instead of magic numbers. At least you could write either
#define N 14
before main
or
const int N = 14.
and use the variable N everywhere where you are using magic number 14.
By the way according to the C Standard function main without parameters shall be declared like
int main( void )
The variable *board is a pointer, but you only allocate one byte for each array element, which should be
#define DIM 14
board = malloc(DIM * sizeof *board);
Following that up with the second allocation
board[i] = malloc(DIM * sizeof **board);
This also allows (a) that the dimension 14 is hard coded in only one place in the program and (b) the allocation will survive if you later make the board's element a different type, for example a struct, as the program develops.