suma - programa de matrices en c
Devolviendo una matriz usando C (10)
Soy relativamente nuevo en C y necesito ayuda con los métodos relacionados con las matrices. Procedente de la programación de Java, estoy acostumbrado a poder decir int [] method()
para devolver una matriz. Sin embargo, descubrí que con C tienes que usar punteros para matrices cuando las devuelves. Siendo un programador nuevo, realmente no entiendo esto en absoluto, incluso con los muchos foros que he examinado.
Básicamente, estoy tratando de escribir un método que devuelva una matriz char en C. Proporcionaré el método (vamos a llamarlo returnArray) con una matriz. Creará una nueva matriz de la matriz anterior y le devolverá un puntero. Solo necesito ayuda sobre cómo comenzar y cómo leer el puntero una vez que se envía fuera de la matriz. Se agradece cualquier ayuda para explicar esto.
Formato de código propuesto para la función de retorno de matriz
char *returnArray(char array []){
char returned [10];
//methods to pull values from array, interpret them, and then create new array
return &(returned[0]); //is this correct?
}
Llamador de la función
int main(){
int i=0;
char array []={1,0,0,0,0,1,1};
char arrayCount=0;
char* returnedArray = returnArray(&arrayCount); ///is this correct?
for (i=0; i<10;i++)
printf(%d, ",", returnedArray[i]); //is this correctly formatted?
}
No he probado esto todavía porque mi compilador de C no funciona en este momento, pero me gustaría resolverlo
¿Qué tal esta implementación deliciosamente malvada?
array.h
#define IMPORT_ARRAY(TYPE) /
/
struct TYPE##Array { /
TYPE* contents; /
size_t size; /
}; /
/
struct TYPE##Array new_##TYPE##Array() { /
struct TYPE##Array a; /
a.contents = NULL; /
a.size = 0; /
return a; /
} /
/
void array_add(struct TYPE##Array* o, TYPE value) { /
TYPE* a = malloc((o->size + 1) * sizeof(TYPE)); /
TYPE i; /
for(i = 0; i < o->size; ++i) { /
a[i] = o->contents[i]; /
} /
++(o->size); /
a[o->size - 1] = value; /
free(o->contents); /
o->contents = a; /
} /
void array_destroy(struct TYPE##Array* o) { /
free(o->contents); /
} /
TYPE* array_begin(struct TYPE##Array* o) { /
return o->contents; /
} /
TYPE* array_end(struct TYPE##Array* o) { /
return o->contents + o->size; /
}
C Principal
#include <stdlib.h>
#include "array.h"
IMPORT_ARRAY(int);
struct intArray return_an_array() {
struct intArray a;
a = new_intArray();
array_add(&a, 1);
array_add(&a, 2);
array_add(&a, 3);
return a;
}
int main() {
struct intArray a;
int* it;
int* begin;
int* end;
a = return_an_array();
begin = array_begin(&a);
end = array_end(&a);
for(it = begin; it != end; ++it) {
printf("%d ", *it);
}
array_destroy(&a);
getchar();
return 0;
}
Aquí un pequeño ejemplo con las diferentes opciones para pasar cadenas y cadenas de retorno.
//include DPI
#include "svdpi.h"
//include the IO files
#include <stdio.h>
//include string functions
#include <string.h>
//include use of malloc
#include <stdlib.h>
//to add the ability to use printf
// same inputs as defined in SV
/* function declaration text char stream passed as pointer value and text2 passed as pointer reference */
char * return_string_in_c( char *text, char **text2) {
char *fix="This variable cannot be changed although it is a pointer, just as example";/*fix allocation and constant*/
char dest[50]="Variable array created in a function:";/* String array max 50 chars allocated*/
char *out = malloc(sizeof(char) * 100);/* Dynamic string max 100 chars allocated*/
/* Concatenate input text and put in out of strcat*/
strcat(out, text);/* initialize out using strcat and text string*/
printf("fix : |%s|,dest : |%s|,text : |%s|,out : |%s|/n", fix,dest,text,out);
*text2=dest;/* allocate pointer value with dest*/
*text2=out;/* now do the same overwrite allocate pointer value with out*/
return out;
}
/* main */
void main() {
char text[100]="from_main_text_variable";/*max 100 chars allocated*/
char *text2;/* pointer not allocated*/
char *point = return_string_in_c(text, &text2);/* &text2 passing by reference*/
printf("Final destination string : |%s|/n", text2);
printf("point output : |%s|/n", point);
}
El resultado será:
fix: | Esta variable no se puede cambiar aunque sea un puntero, solo como ejemplo |, dest: | Variable array creado en una función: |, text: | from_main_text_variable |, out: | from_main_text_variable |
Cadena de destino final: | from_main_text_variable |
punto de salida: | from_main_text_variable |
Declare su matriz como una variable global para que cada función pueda editarla. Aquí hay un ejemplo :
#include<stdio.h>
#include<conio.h>
char a[1000];
void edit(char b);
main()
{
edit(a);
printf("%s", a);
}
void edit(char b)
{
for(int i=0;i<sizeof(b);i++)
a[i]=i;
}
El tratamiento de las matrices de C es muy diferente al de Java, y tendrás que ajustar tu forma de pensar en consecuencia. Las matrices en C no son objetos de primera clase (es decir, una expresión de matriz no conserva su "matriz" en la mayoría de los contextos). En C, una expresión de tipo "matriz de elementos N de T
" se convertirá implícitamente ("decaimiento") a una expresión de tipo "puntero a T
", excepto cuando la expresión de matriz es un operando del sizeof
o unario &
operadores o si la expresión de matriz es un literal de cadena que se usa para inicializar otra matriz en una declaración.
Entre otras cosas, esto significa que no puede pasar una expresión de matriz a una función y hacer que se reciba como un tipo de matriz ; la función en realidad recibe un tipo de puntero:
void foo(char *a, size_t asize)
{
// do something with a
}
int bar(void)
{
char str[6] = "Hello";
foo(str, sizeof str);
}
En la llamada a foo
, la expresión str
se convierte de tipo char [6]
a char *
, por lo que el primer parámetro de foo
se declara char *a
lugar de char a[6]
. En sizeof str
, dado que la expresión de matriz es un operando del operador sizeof
, no se convierte a un tipo de puntero, por lo que se obtiene el número de bytes en la matriz (6).
Si está realmente interesado, puede leer El desarrollo del lenguaje C de Dennis Ritchie para comprender de dónde viene este tratamiento.
El resultado es que las funciones no pueden devolver tipos de matriz, lo cual está bien ya que las expresiones de matriz tampoco pueden ser el objetivo de una asignación.
El método más seguro es que la persona que llama defina la matriz y pase su dirección y tamaño a la función que se supone que debe escribir en ella:
void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize)
{
...
dstArray[i] = some_value_derived_from(srcArray[i]);
...
}
int main(void)
{
char src[] = "This is a test";
char dst[sizeof src];
...
returnArray(src, sizeof src, dst, sizeof dst);
...
}
Otro método es que la función asigne dinámicamente la matriz y devuelva el puntero y el tamaño:
char *returnArray(const char *srcArray, size_t srcSize, size_t *dstSize)
{
char *dstArray = malloc(srcSize);
if (dstArray)
{
*dstSize = srcSize;
...
}
return dstArray;
}
int main(void)
{
char src[] = "This is a test";
char *dst;
size_t dstSize;
dst = returnArray(src, sizeof src, &dstSize);
...
free(dst);
...
}
En este caso, la persona que llama es responsable de desasignar la matriz con la función de biblioteca free
.
Tenga en cuenta que dst
en el código anterior es un simple puntero a char
, no un puntero a una matriz de char
. La semántica del puntero y la matriz de C es tal que puede aplicar el operador de subíndice []
a una expresión de tipo de matriz o tipo de puntero; tanto src[i]
como dst[i]
accederán al i
-ésimo elemento de la matriz (aunque src
solo tenga el tipo de matriz).
Puede declarar un puntero a un conjunto de N elementos de T
y hacer algo similar:
char (*returnArray(const char *srcArr, size_t srcSize))[SOME_SIZE]
{
char (*dstArr)[SOME_SIZE] = malloc(sizeof *dstArr);
if (dstArr)
{
...
(*dstArr)[i] = ...;
...
}
return dstArr;
}
int main(void)
{
char src[] = "This is a test";
char (*dst)[SOME_SIZE];
...
dst = returnArray(src, sizeof src);
...
printf("%c", (*dst)[j]);
...
}
Varios inconvenientes con lo anterior. En primer lugar, las versiones anteriores de C esperan que SOME_SIZE
sea una constante en tiempo de compilación, lo que significa que la función solo funcionará con un tamaño de matriz. En segundo lugar, debe desreferenciar el puntero antes de aplicar el subíndice, que satura el código. Los punteros a las matrices funcionan mejor cuando se trata de matrices multidimensionales.
En su caso, está creando una matriz en la pila y una vez que abandona el alcance de la función, la matriz será desasignada. En su lugar, cree una matriz dinámicamente asignada y devuelva un puntero a ella.
char * returnArray(char *arr, int size) {
char *new_arr = malloc(sizeof(char) * size);
for(int i = 0; i < size; ++i) {
new_arr[i] = arr[i];
}
return new_arr;
}
int main() {
char arr[7]= {1,0,0,0,0,1,1};
char *new_arr = returnArray(arr, 7);
// don''t forget to free the memory after you''re done with the array
free(new_arr);
}
No estoy diciendo que esta sea la mejor solución o una solución preferida para el problema dado. Sin embargo, puede ser útil recordar que las funciones pueden devolver estructuras. Aunque las funciones no pueden devolver matrices, las matrices pueden ser envueltas en estructuras y la función puede devolver la estructura, llevando así la matriz con ella. Esto funciona para arreglos de longitud fija.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef
struct
{
char v[10];
} CHAR_ARRAY;
CHAR_ARRAY returnArray(CHAR_ARRAY array_in, int size)
{
CHAR_ARRAY returned;
/*
. . . methods to pull values from array, interpret them, and then create new array
*/
for (int i = 0; i < size; i++ )
returned.v[i] = array_in.v[i] + 1;
return returned; // Works!
}
int main(int argc, char * argv[])
{
CHAR_ARRAY array = {1,0,0,0,0,1,1};
char arrayCount = 7;
CHAR_ARRAY returnedArray = returnArray(array, arrayCount);
for (int i = 0; i < arrayCount; i++)
printf("%d, ", returnedArray.v[i]); //is this correctly formatted?
getchar();
return 0;
}
Invito a comentarios sobre las fortalezas y debilidades de esta técnica. No me he molestado en hacerlo.
No puede devolver matrices de funciones en C. También no puede (no debería) hacer esto:
char *returnArray(char array []){
char returned [10];
//methods to pull values from array, interpret them, and then create new array
return &(returned[0]); //is this correct?
}
returned
se crea con una duración de almacenamiento automática y las referencias a él se invalidarán una vez que salga de su ámbito de declaración, es decir, cuando la función regrese.
Tendrá que asignar dinámicamente la memoria dentro de la función o llenar un búfer preasignado provisto por la persona que llama.
Opción 1:
asignar dinámicamente la memoria dentro de la función (la persona que llama es responsable de la desasignación de ret
)
char *foo(int count) {
char *ret = malloc(count);
if(!ret)
return NULL;
for(int i = 0; i < count; ++i)
ret[i] = i;
return ret;
}
Llámalo así:
int main() {
char *p = foo(10);
if(p) {
// do stuff with p
free(p);
}
return 0;
}
Opcion 2:
llenar un búfer preasignado proporcionado por la persona que llama (la persona que llama asigna buf
y pasa a la función)
void foo(char *buf, int count) {
for(int i = 0; i < count; ++i)
buf[i] = i;
}
Y llámalo así:
int main() {
char arr[10] = {0};
foo(arr, 10);
// No need to deallocate because we allocated
// arr with automatic storage duration.
// If we had dynamically allocated it
// (i.e. malloc or some variant) then we
// would need to call free(arr)
}
Puede hacerlo utilizando la memoria de pila (a través de la invocación de malloc () ) como otras respuestas informadas aquí, pero siempre debe administrar la memoria (use la función gratuita () cada vez que llame a su función). También puede hacerlo con una matriz estática:
char* returnArrayPointer()
{
static char array[SIZE];
// do something in your array here
return array;
}
Puede usarlo sin preocuparse por la administración de la memoria.
int main()
{
char* myArray = returnArrayPointer();
/* use your array here */
/* don''t worry to free memory here */
}
En este ejemplo, debe usar palabras clave estáticas en la definición de matriz para establecer en toda la aplicación la duración de la matriz, por lo que no se destruirá después de la declaración de devolución. Por supuesto, de esta forma ocupará TAMAÑO de bytes en su memoria durante toda la vida útil de la aplicación, ¡así que dimensionela correctamente!
Puedes usar un código como este:
char *MyFunction(some arguments...)
{
char *pointer = malloc(size for the new array);
if (!pointer)
An error occurred, abort or do something about the error.
return pointer; // Return address of memory to the caller.
}
Cuando haga esto, la memoria se liberará más tarde, pasando la dirección a libre.
Hay otras opciones Una rutina puede devolver un puntero a una matriz (o parte de una matriz) que es parte de alguna estructura existente. La persona que llama puede pasar una matriz, y la rutina simplemente escribe en la matriz, en lugar de asignar espacio para una nueva matriz.
Su método devolverá una variable de pila local que fallará gravemente. Para devolver una matriz, cree una fuera de la función, pase la dirección por la función, luego modifíquela o cree una matriz en el montón y devuelva esa variable. Ambos funcionarán, pero el primero no requiere ninguna asignación de memoria dinámica para que funcione correctamente.
void returnArray(int size, char *retArray)
{
// work directly with retArray or memcpy into it from elsewhere like
// memcpy(retArray, localArray, size);
}
#define ARRAY_SIZE 20
int main(void)
{
char foo[ARRAY_SIZE];
returnArray(ARRAY_SIZE, foo);
}